diff options
author | Luca Falavigna <dktrkranz@debian.org> | 2010-01-02 20:56:35 +0100 |
---|---|---|
committer | Luca Falavigna <dktrkranz@debian.org> | 2010-01-02 20:56:35 +0100 |
commit | 64c458487151933ee0ba093cf4ac69e177d9be37 (patch) | |
tree | f6e3755704f53406eea85532e4ffe5d5ef50b7f0 /doc/user | |
parent | 2aec9cc58398cac1376509a7d75edb83b41f984e (diff) | |
parent | 72c578fd4b0b4a5a43e18594339ac4ff26c376dc (diff) |
Merge commit 'upstream/1.2.0.d20091224'
Diffstat (limited to 'doc/user')
99 files changed, 43207 insertions, 0 deletions
diff --git a/doc/user/MANIFEST b/doc/user/MANIFEST new file mode 100644 index 0000000..ef273d3 --- /dev/null +++ b/doc/user/MANIFEST @@ -0,0 +1,50 @@ +actions.xml +add-method.xml +alias.xml +ant.xml +builders.xml +builders-built-in.xml +builders-commands.xml +builders-writing.xml +build-install.xml +caching.xml +command-line.xml +cons.pl +copyright.xml +depends.xml +environments.xml +errors.xml +example.xml +factories.xml +file-removal.xml +hierarchy.xml +install.xml +java.xml +libraries.xml +less-simple.xml +main.xml +make.xml +mergeflags.xml +misc.xml +nodes.xml +output.xml +parseconfig.xml +parseflags.xml +preface.xml +python.xml +repositories.xml +run.xml +scanners.xml +sconf.xml +separate.xml +simple.xml +sourcecode.xml +tasks.xml +tools.xml +troubleshoot.xml +variants.xml +variables.xml +SCons-win32-install-1.jpg +SCons-win32-install-2.jpg +SCons-win32-install-3.jpg +SCons-win32-install-4.jpg diff --git a/doc/user/README b/doc/user/README new file mode 100644 index 0000000..aef479a --- /dev/null +++ b/doc/user/README @@ -0,0 +1,21 @@ +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + +When adding a new file, add it to main.xml and MANIFEST. + +To build the .xml files from the .in files: + scons -D BUILDDOC=1 foo.xml +To build the whole PDF doc from this dir, for testing: + scons -D ../../build/doc/PDF/scons-user.pdf + +Writing examples: here's a simple template. + + <scons_example name="Foo"> + <file name="SConstruct"> + env = Environment() + print env.Dump("CC") + </file> + </scons_example> + + <scons_output example="Foo"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> diff --git a/doc/user/SCons-win32-install-1.jpg b/doc/user/SCons-win32-install-1.jpg Binary files differnew file mode 100644 index 0000000..ecc439d --- /dev/null +++ b/doc/user/SCons-win32-install-1.jpg diff --git a/doc/user/SCons-win32-install-2.jpg b/doc/user/SCons-win32-install-2.jpg Binary files differnew file mode 100644 index 0000000..f468526 --- /dev/null +++ b/doc/user/SCons-win32-install-2.jpg diff --git a/doc/user/SCons-win32-install-3.jpg b/doc/user/SCons-win32-install-3.jpg Binary files differnew file mode 100644 index 0000000..90d2ed4 --- /dev/null +++ b/doc/user/SCons-win32-install-3.jpg diff --git a/doc/user/SCons-win32-install-4.jpg b/doc/user/SCons-win32-install-4.jpg Binary files differnew file mode 100644 index 0000000..d37973b --- /dev/null +++ b/doc/user/SCons-win32-install-4.jpg diff --git a/doc/user/actions.in b/doc/user/actions.in new file mode 100644 index 0000000..1ea5c49 --- /dev/null +++ b/doc/user/actions.in @@ -0,0 +1,404 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; supports several types of &build_actions; + that can be performed to build one or more target files. + Usually, a &build_action; is a command-line string + that invokes an external command. + A build action can also be an external command + specified as a list of arguments, + or even a Python function. + + </para> + + <para> + + Build action objects are created by the &Action; function. + This function is, in fact, what &SCons; uses + to interpret the &action; + keyword argument when you call the &Builder; function. + So the following line that creates a simple Builder: + + </para> + + <sconstruct> + b = Builder(action = 'build < $SOURCE > $TARGET') + </sconstruct> + + <para> + + Is equivalent to: + + </para> + + <sconstruct> + b = Builder(action = Action('build < $SOURCE > $TARGET')) + </sconstruct> + + <para> + + The advantage of using the &Action; function directly + is that it can take a number of additional options + to modify the action's behavior in many useful ways. + + </para> + + <section> + <title>Command Strings as Actions</title> + + <section> + <title>Suppressing Command-Line Printing</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Ignoring Exit Status</title> + + <para> + + XXX + + </para> + + </section> + + </section> + + <section> + <title>Argument Lists as Actions</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Python Functions as Actions</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Modifying How an Action is Printed</title> + + <section> + <title>XXX: the &strfunction; keyword argument</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>XXX: the &cmdstr; keyword argument</title> + + <para> + + XXX + + </para> + + </section> + + </section> + + <section> + <title>Making an Action Depend on Variable Contents: the &varlist; keyword argument</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>chdir=1</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Batch Building of Multiple Targets from Separate Sources: the &batch_key; keyword argument</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Manipulating the Exit Status of an Action: the &exitstatfunc; keyword argument</title> + + <para> + + XXX + + </para> + + </section> + + <!-- + + ??? + + <section> + <title>presub=</title> + + <para> + + XXX + + </para> + + </section> + + --> diff --git a/doc/user/actions.xml b/doc/user/actions.xml new file mode 100644 index 0000000..c3b8cf9 --- /dev/null +++ b/doc/user/actions.xml @@ -0,0 +1,404 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; supports several types of &build_actions; + that can be performed to build one or more target files. + Usually, a &build_action; is a command-line string + that invokes an external command. + A build action can also be an external command + specified as a list of arguments, + or even a Python function. + + </para> + + <para> + + Build action objects are created by the &Action; function. + This function is, in fact, what &SCons; uses + to interpret the &action; + keyword argument when you call the &Builder; function. + So the following line that creates a simple Builder: + + </para> + + <programlisting> + b = Builder(action = 'build < $SOURCE > $TARGET') + </programlisting> + + <para> + + Is equivalent to: + + </para> + + <programlisting> + b = Builder(action = Action('build < $SOURCE > $TARGET')) + </programlisting> + + <para> + + The advantage of using the &Action; function directly + is that it can take a number of additional options + to modify the action's behavior in many useful ways. + + </para> + + <section> + <title>Command Strings as Actions</title> + + <section> + <title>Suppressing Command-Line Printing</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Ignoring Exit Status</title> + + <para> + + XXX + + </para> + + </section> + + </section> + + <section> + <title>Argument Lists as Actions</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Python Functions as Actions</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Modifying How an Action is Printed</title> + + <section> + <title>XXX: the &strfunction; keyword argument</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>XXX: the &cmdstr; keyword argument</title> + + <para> + + XXX + + </para> + + </section> + + </section> + + <section> + <title>Making an Action Depend on Variable Contents: the &varlist; keyword argument</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>chdir=1</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Batch Building of Multiple Targets from Separate Sources: the &batch_key; keyword argument</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Manipulating the Exit Status of an Action: the &exitstatfunc; keyword argument</title> + + <para> + + XXX + + </para> + + </section> + + <!-- + + ??? + + <section> + <title>presub=</title> + + <para> + + XXX + + </para> + + </section> + + --> diff --git a/doc/user/add-method.in b/doc/user/add-method.in new file mode 100644 index 0000000..61f13cc --- /dev/null +++ b/doc/user/add-method.in @@ -0,0 +1,127 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + The &AddMethod; function is used to add a method + to an environment. It's typically used to add a "pseudo-builder," + a function that looks like a &Builder; but + wraps up calls to multiple other &Builder;s + or otherwise processes its arguments + before calling one or more &Builder;s. + In the following example, + we want to install the program into the standard + <filename>/usr/bin</filename> directory hierarchy, + but also copy it into a local <filename>install/bin</filename> + directory from which a package might be built: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + def install_in_bin_dirs(env, source): + """Install source in both bin dirs""" + i1 = env.Install("$BIN", source) + i2 = env.Install("$LOCALBIN", source) + return [i1[0], i2[0]] # Return a list, like a normal builder + env = Environment(BIN='__ROOT__/usr/bin', LOCALBIN='#install/bin') + env.AddMethod(install_in_bin_dirs, "InstallInBinDirs") + env.InstallInBinDirs(Program('hello.c')) # installs hello in both bin dirs + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + This produces the following: + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q /</scons_output_command> + </scons_output> + + <para> + + As mentioned, a psuedo-builder also provides more flexibility + in parsing arguments than you can get with a &Builder;. + The next example shows a pseudo-builder with a + named argument that modifies the filename, and a separate argument + for the resource file (rather than having the builder figure it out + by file extension). This example also demonstrates using the global + &AddMethod; function to add a method to the global Environment class, + so it will be used in all subsequently created environments. + + </para> + + <scons_example name="ex2"> + <file name="SConstruct" printme="1"> + def BuildTestProg(env, testfile, resourcefile, testdir="tests"): + """Build the test program; + prepends "test_" to src and target, + and puts target into testdir.""" + srcfile = "test_%s.c" % testfile + target = "%s/test_%s" % (testdir, testfile) + if env['PLATFORM'] == 'win32': + resfile = env.RES(resourcefile) + p = env.Program(target, [srcfile, resfile]) + else: + p = env.Program(target, srcfile) + return p + AddMethod(Environment, BuildTestProg) + + env = Environment() + env.BuildTestProg('stuff', resourcefile='res.rc') + </file> + <file name="test_stuff.c"> + int main() { printf("Hello, world!\n"); } + </file> + <file name="res.rc"> + res.rc + </file> + </scons_example> + + <para> + This produces the following on Linux: + </para> + + <scons_output example="ex2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + And the following on Windows: + </para> + + <scons_output example="ex2" os="win32"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + Using &AddMethod; is better than just adding an instance method + to a &consenv; because it gets called as a proper method, + and because &AddMethod; provides for copying the method + to any clones of the &consenv; instance. + </para> diff --git a/doc/user/add-method.xml b/doc/user/add-method.xml new file mode 100644 index 0000000..761765f --- /dev/null +++ b/doc/user/add-method.xml @@ -0,0 +1,135 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + The &AddMethod; function is used to add a method + to an environment. It's typically used to add a "pseudo-builder," + a function that looks like a &Builder; but + wraps up calls to multiple other &Builder;s + or otherwise processes its arguments + before calling one or more &Builder;s. + In the following example, + we want to install the program into the standard + <filename>/usr/bin</filename> directory hierarchy, + but also copy it into a local <filename>install/bin</filename> + directory from which a package might be built: + + </para> + + <programlisting> + def install_in_bin_dirs(env, source): + """Install source in both bin dirs""" + i1 = env.Install("$BIN", source) + i2 = env.Install("$LOCALBIN", source) + return [i1[0], i2[0]] # Return a list, like a normal builder + env = Environment(BIN='/usr/bin', LOCALBIN='#install/bin') + env.AddMethod(install_in_bin_dirs, "InstallInBinDirs") + env.InstallInBinDirs(Program('hello.c')) # installs hello in both bin dirs + </programlisting> + + <para> + This produces the following: + </para> + + <screen> + % <userinput>scons -Q /</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + Install file: "hello" as "/usr/bin/hello" + Install file: "hello" as "install/bin/hello" + </screen> + + <para> + + As mentioned, a psuedo-builder also provides more flexibility + in parsing arguments than you can get with a &Builder;. + The next example shows a pseudo-builder with a + named argument that modifies the filename, and a separate argument + for the resource file (rather than having the builder figure it out + by file extension). This example also demonstrates using the global + &AddMethod; function to add a method to the global Environment class, + so it will be used in all subsequently created environments. + + </para> + + <programlisting> + def BuildTestProg(env, testfile, resourcefile, testdir="tests"): + """Build the test program; + prepends "test_" to src and target, + and puts target into testdir.""" + srcfile = "test_%s.c" % testfile + target = "%s/test_%s" % (testdir, testfile) + if env['PLATFORM'] == 'win32': + resfile = env.RES(resourcefile) + p = env.Program(target, [srcfile, resfile]) + else: + p = env.Program(target, srcfile) + return p + AddMethod(Environment, BuildTestProg) + + env = Environment() + env.BuildTestProg('stuff', resourcefile='res.rc') + </programlisting> + + <para> + This produces the following on Linux: + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o test_stuff.o -c test_stuff.c + cc -o tests/test_stuff test_stuff.o + </screen> + + <para> + And the following on Windows: + </para> + + <screen> + C:\><userinput>scons -Q</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + rc /fores.res res.rc + cl /Fotest_stuff.obj /c test_stuff.c /nologo + link /nologo /OUT:tests\test_stuff.exe test_stuff.obj res.res + </screen> + + <para> + Using &AddMethod; is better than just adding an instance method + to a &consenv; because it gets called as a proper method, + and because &AddMethod; provides for copying the method + to any clones of the &consenv; instance. + </para> diff --git a/doc/user/alias.in b/doc/user/alias.in new file mode 100644 index 0000000..45a1534 --- /dev/null +++ b/doc/user/alias.in @@ -0,0 +1,102 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + We've already seen how you can use the &Alias; + function to create a target named <literal>install</literal>: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + env = Environment() + hello = env.Program('hello.c') + env.Install('__ROOT__/usr/bin', hello) + env.Alias('install', '__ROOT__/usr/bin') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + You can then use this alias on the command line + to tell &SCons; more naturally that you want to install files: + + </para> + + <scons_output example="ex1" os="posix"> + <scons_output_command>scons -Q install</scons_output_command> + </scons_output> + + <para> + + Like other &Builder; methods, though, + the &Alias; method returns an object + representing the alias being built. + You can then use this object as input to anothother &Builder;. + This is especially useful if you use such an object + as input to another call to the &Alias; &Builder;, + allowing you to create a hierarchy + of nested aliases: + + </para> + + <scons_example name="ex2"> + <file name="SConstruct" printme="1"> + env = Environment() + p = env.Program('foo.c') + l = env.Library('bar.c') + env.Install('__ROOT__/usr/bin', p) + env.Install('__ROOT__/usr/lib', l) + ib = env.Alias('install-bin', '__ROOT__/usr/bin') + il = env.Alias('install-lib', '__ROOT__/usr/lib') + env.Alias('install', [ib, il]) + </file> + <file name="foo.c"> + int main() { printf("foo.c\n"); } + </file> + <file name="bar.c"> + void bar() { printf("bar.c\n"); } + </file> + </scons_example> + + <para> + + This example defines separate <literal>install</literal>, + <literal>install-bin</literal>, + and <literal>install-lib</literal> aliases, + allowing you finer control over what gets installed: + + </para> + + <scons_output example="ex2" os="posix"> + <scons_output_command>scons -Q install-bin</scons_output_command> + <scons_output_command>scons -Q install-lib</scons_output_command> + <scons_output_command>scons -Q -c __ROOT__/</scons_output_command> + <scons_output_command>scons -Q install</scons_output_command> + </scons_output> diff --git a/doc/user/alias.xml b/doc/user/alias.xml new file mode 100644 index 0000000..04ebd5f --- /dev/null +++ b/doc/user/alias.xml @@ -0,0 +1,112 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + We've already seen how you can use the &Alias; + function to create a target named <literal>install</literal>: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.Install('/usr/bin', hello) + env.Alias('install', '/usr/bin') + </programlisting> + + <para> + + You can then use this alias on the command line + to tell &SCons; more naturally that you want to install files: + + </para> + + <screen> + % <userinput>scons -Q install</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + Install file: "hello" as "/usr/bin/hello" + </screen> + + <para> + + Like other &Builder; methods, though, + the &Alias; method returns an object + representing the alias being built. + You can then use this object as input to anothother &Builder;. + This is especially useful if you use such an object + as input to another call to the &Alias; &Builder;, + allowing you to create a hierarchy + of nested aliases: + + </para> + + <programlisting> + env = Environment() + p = env.Program('foo.c') + l = env.Library('bar.c') + env.Install('/usr/bin', p) + env.Install('/usr/lib', l) + ib = env.Alias('install-bin', '/usr/bin') + il = env.Alias('install-lib', '/usr/lib') + env.Alias('install', [ib, il]) + </programlisting> + + <para> + + This example defines separate <literal>install</literal>, + <literal>install-bin</literal>, + and <literal>install-lib</literal> aliases, + allowing you finer control over what gets installed: + + </para> + + <screen> + % <userinput>scons -Q install-bin</userinput> + cc -o foo.o -c foo.c + cc -o foo foo.o + Install file: "foo" as "/usr/bin/foo" + % <userinput>scons -Q install-lib</userinput> + cc -o bar.o -c bar.c + ar rc libbar.a bar.o + ranlib libbar.a + Install file: "libbar.a" as "/usr/lib/libbar.a" + % <userinput>scons -Q -c /</userinput> + Removed foo.o + Removed foo + Removed /usr/bin/foo + Removed bar.o + Removed libbar.a + Removed /usr/lib/libbar.a + % <userinput>scons -Q install</userinput> + cc -o foo.o -c foo.c + cc -o foo foo.o + Install file: "foo" as "/usr/bin/foo" + cc -o bar.o -c bar.c + ar rc libbar.a bar.o + ranlib libbar.a + Install file: "libbar.a" as "/usr/lib/libbar.a" + </screen> diff --git a/doc/user/ant.in b/doc/user/ant.in new file mode 100644 index 0000000..41b441d --- /dev/null +++ b/doc/user/ant.in @@ -0,0 +1,52 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + XXX + + </para> + + <section> + <title>Differences Between &Ant; and &SCons;</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Advantages of &SCons; Over &Ant;</title> + + <para> + + XXX + + </para> + + </section> diff --git a/doc/user/ant.xml b/doc/user/ant.xml new file mode 100644 index 0000000..41b441d --- /dev/null +++ b/doc/user/ant.xml @@ -0,0 +1,52 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + XXX + + </para> + + <section> + <title>Differences Between &Ant; and &SCons;</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Advantages of &SCons; Over &Ant;</title> + + <para> + + XXX + + </para> + + </section> diff --git a/doc/user/build-install.in b/doc/user/build-install.in new file mode 100644 index 0000000..ab289b1 --- /dev/null +++ b/doc/user/build-install.in @@ -0,0 +1,719 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + This chapter will take you through the basic steps + of installing &SCons; on your system, + and building &SCons; if you don't have a + pre-built package available + (or simply prefer the flexibility of building it yourself). + Before that, however, this chapter will also describe the basic steps + involved in installing Python on your system, + in case that is necessary. + Fortunately, both &SCons; and Python + are very easy to install on almost any system, + and Python already comes installed on many systems. + + </para> + + <!-- + + <para> + + Lastly, this chapter also contains a section that + provides a brief overview of the Python programming language, + which is the language used to implement &SCons;, + and which forms the basis of the &SCons; configuration files. + Becoming familiar with some Python concepts will make it easier + to understand many of the examples in this User's Guide. + Nevertheless, it <emphasis>is</emphasis> possible + to configure simple &SCons; builds without knowing Python, + so you can skip this section if you + want to dive in and pick up things + by example- -or, of course, if you are + already familiar with Python. + + </para> + + --> + + <section> + <title>Installing Python</title> + + <para> + + Because &SCons; is written in Python, + you must obviously have Python installed on your system + to use &SCons;. + Before you try to install Python, + you should check to see if Python is already + available on your system by typing + <userinput>python -V</userinput> + (capital 'V') + or + <userinput>python --version</userinput> + at your system's command-line prompt. + + </para> + + <screen> + $ <userinput>python -V</userinput> + Python 2.5.1 + </screen> + + <para> + + And on a Windows system with Python installed: + + </para> + + <screen> + C:\><userinput>python -V</userinput> + Python 2.5.1 + </screen> + + <para> + + If Python is not installed on your system, + you will see an error message + stating something like "command not found" + (on UNIX or Linux) + or "'python' is not recognized + as an internal or external command, operable progam or batch file" + (on Windows). + In that case, you need to install Python + before you can install &SCons;. + + </para> + + <para> + + (Note that the <option>-V</option> option + was added to Python version 2.0, + so if your system only has an earlier version available + you may see an + <literal>"Unknown option: -V"</literal> + error message.) + + </para> + + <para> + + The standard location for information + about downloading and installing Python is + <ulink url="http://www.python.org/download/">http://www.python.org/download/</ulink>. + See that page for information about + how to download and install Python on your system. + + </para> + + <para> + + &SCons; will work with any version of Python from 1.5.2 or later. + If you need to install Python and have a choice, + we recommend using the most recent Python 2.5 version available. + Python 2.5 has significant improvements + that help speed up the performance of &SCons;. + + </para> + + </section> + + <section> + <title>Installing &SCons; From Pre-Built Packages</title> + + <para> + + &SCons; comes pre-packaged for installation on a number of systems, + including Linux and Windows systems. + You do not need to read this entire section, + you should need to read only the section + appropriate to the type of system you're running on. + + </para> + + <section> + <title>Installing &SCons; on Red Hat (and Other RPM-based) Linux Systems</title> + + <para> + + &SCons; comes in RPM (Red Hat Package Manager) format, + pre-built and ready to install on Red Hat Linux, + Fedora, + or any other Linux distribution that uses RPM. + Your distribution may + already have an &SCons; RPM built specifically for it; + many do, including SUSE, Mandrake and Fedora. + You can check for the availability of an &SCons; RPM + on your distribution's download servers, + or by consulting an RPM search site like + <ulink url="http://www.rpmfind.net/">http://www.rpmfind.net/</ulink> or + <ulink url="http://rpm.pbone.net/">http://rpm.pbone.net/</ulink>. + + </para> + + <para> + + If your distribution supports installation via + <application>yum</application>, + you should be able to install &SCons; by running: + + </para> + + <screen> + # <userinput>yum install scons</userinput> + </screen> + + <para> + + If your Linux distribution does not already have + a specific &SCons; RPM file, + you can download and install from the + generic RPM provided by the &SCons; project. + This will install the + SCons script(s) in <filename>/usr/bin</filename>, + and the SCons library modules in + <filename>/usr/lib/scons</filename>. + + </para> + + <para> + + To install from the command line, simply download the + appropriate <filename>.rpm</filename> file, + and then run: + + </para> + + <screen> + # <userinput>rpm -Uvh scons-1.2.0.d20091224-1.noarch.rpm</userinput> + </screen> + + <para> + + Or, you can use a graphical RPM package manager. + See your package manager application's documention + for specific instructions about + how to use it to install a downloaded RPM. + + </para> + + </section> + + <section> + <title>Installing &SCons; on Debian Linux Systems</title> + + <para> + + Debian Linux systems use a different package management + format that also makes it very easy to install &SCons;. + + </para> + + <para> + + If your system is connected to the Internet, + you can install the latest official Debian package + by running: + + </para> + + <screen> + # <userinput>apt-get install scons</userinput> + </screen> + + <!-- + + <para> + + Alternatively, + you can download the Debian package built + by the &SCons; project + and install it manually by running: + + </para> + + <screen> + # <userinput>db-XXX scons-*.deb</userinput> + </screen> + + --> + + </section> + + <section> + <title>Installing &SCons; on Windows Systems</title> + + <para> + + &SCons; provides a Windows installer + that makes installation extremely easy. + Download the <filename>scons-1.2.0.d20091224.win32.exe</filename> + file from the &SCons; download page at + <ulink url="http://www.scons.org/download.php">http://www.scons.org/download.php</ulink>. + Then all you need to do is execute the file + (usually by clicking on its icon in Windows Explorer). + These will take you through a small + sequence of windows that will install + &SCons; on your system. + + <!-- + Things are a little more complicated + if you are using the Cygwin version of Python. + This is because Cygwin + tries to make a Windows system look more + POSIX-like (or UNIX-like or Linux-like, if you prefer) + by having the Cygwin utilities, + including Cygwin Python, + interpret file name arguments on the command line + using the forward-slash (<filename>/</filename>) + as the directory separator, + instead of the normal Windows behavior of the + backslash (<filename>\</filename>) as the directory separator. + --> + + </para> + + <!-- + + <section> + <title>Installing &SCons; on Windows Systems Without Cygwin Python</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Installing &SCons; on Windows Systems With Cygwin Python</title> + + <para> + + XXX + + </para> + + </section> + + --> + + <!-- + + XXX - don't have the kinks worked out on how to + get these to display properly in all formats, + so comment them out for now. + + <screenshot> + <mediaobject> + <imageobject> + <imagedata fileref="SCons-win32-install-1.jpg" format="jpg" align="center"> + </imageobject> + </mediaobject> + </screenshot> + + <screenshot> + <mediaobject> + <imageobject> + <imagedata fileref="SCons-win32-install-2.jpg" format="jpg" align="center"> + </imageobject> + </mediaobject> + </screenshot> + + <screenshot> + <mediaobject> + <imageobject> + <imagedata fileref="SCons-win32-install-3.jpg" format="jpg" align="center"> + </imageobject> + </mediaobject> + </screenshot> + + <screenshot> + <mediaobject> + <imageobject> + <imagedata fileref="SCons-win32-install-4.jpg" format="jpg" align="center"> + </imageobject> + </mediaobject> + </screenshot> + + --> + + </section> + + </section> + + <section> + <title>Building and Installing &SCons; on Any System</title> + + <para> + + If a pre-built &SCons; package is not available for your system, + then you can still easily build and install &SCons; using the native + Python <filename>distutils</filename> package. + + </para> + + <para> + + The first step is to download either the + <filename>scons-1.2.0.d20091224.tar.gz</filename> + or <filename>scons-1.2.0.d20091224.zip</filename>, + which are available from the SCons download page at + <ulink url="http://www.scons.org/download.html">http://www.scons.org/download.html</ulink>. + + </para> + + <para> + + Unpack the archive you downloaded, + using a utility like <application>tar</application> + on Linux or UNIX, + or <application>WinZip</application> on Windows. + This will create a directory called + <filename>scons-1.2.0.d20091224</filename>, + usually in your local directory. + Then change your working directory to that directory + and install &SCons; by executing the following commands: + + </para> + + <screen> + # <userinput>cd scons-1.2.0.d20091224</userinput> + # <userinput>python setup.py install</userinput> + </screen> + + <para> + + This will build &SCons;, + install the &scons; script + in the default system scripts directory + (<filename>/usr/local/bin</filename> or + <filename>C:\Python25\Scripts</filename>), + and will install the &SCons; build engine + in an appropriate stand-alone library directory + (<filename>/usr/local/lib/scons</filename> or + <filename>C:\Python25\scons</filename>). + Because these are system directories, + you may need root (on Linux or UNIX) or Administrator (on Windows) + privileges to install &SCons; like this. + + </para> + + <!-- + + <section> + <title>Building and Installing &SCons; in the Standard Python Library Directories</title> + + <para> + + XXX + + </para> + + </section> + + --> + + <section> + <title>Building and Installing Multiple Versions of &SCons; Side-by-Side</title> + + <para> + + The &SCons; <filename>setup.py</filename> script + has some extensions that support + easy installation of multiple versions of &SCons; + in side-by-side locations. + This makes it easier to download and + experiment with different versions of &SCons; + before moving your official build process to a new version, + for example. + + </para> + + <para> + + To install &SCons; in a version-specific location, + add the <option>--version-lib</option> option + when you call <filename>setup.py</filename>: + + </para> + + <screen> + # <userinput>python setup.py install --version-lib</userinput> + </screen> + + <para> + + This will install the &SCons; build engine + in the + <filename>/usr/lib/scons-1.2.0.d20091224</filename> + or + <filename>C:\Python25\scons-1.2.0.d20091224</filename> + directory, for example. + + </para> + + <para> + + If you use the <option>--version-lib</option> option + the first time you install &SCons;, + you do not need to specify it each time you install + a new version. + The &SCons; <filename>setup.py</filename> script + will detect the version-specific directory name(s) + and assume you want to install all versions + in version-specific directories. + You can override that assumption in the future + by explicitly specifying the <option>--standalone-lib</option> option. + + </para> + + </section> + + <section> + <title>Installing &SCons; in Other Locations</title> + + <para> + + You can install &SCons; in locations other than + the default by specifying the <option>--prefix=</option> option: + + </para> + + <screen> + # <userinput>python setup.py install --prefix=/opt/scons</userinput> + </screen> + + <para> + + This would + install the <application>scons</application> script in + <filename>/opt/scons/bin</filename> + and the build engine in + <filename>/opt/scons/lib/scons</filename>, + + </para> + + <para> + + Note that you can specify both the <option>--prefix=</option> + and the <option>--version-lib</option> options + at the same type, + in which case <filename>setup.py</filename> + will install the build engine + in a version-specific directory + relative to the specified prefix. + Adding <option>--version-lib</option> to the + above example would install the build engine in + <filename>/opt/scons/lib/scons-1.2.0.d20091224</filename>. + + </para> + + </section> + + <section> + <title>Building and Installing &SCons; Without Administrative Privileges</title> + + <para> + + If you don't have the right privileges to install &SCons; + in a system location, + simply use the <literal>--prefix=</literal> option + to install it in a location of your choosing. + For example, + to install &SCons; in appropriate locations + relative to the user's <literal>$HOME</literal> directory, + the &scons; script in + <filename>$HOME/bin</filename> + and the build engine in + <filename>$HOME/lib/scons</filename>, + simply type: + + </para> + + <screen> + $ <userinput>python setup.py install --prefix=$HOME</userinput> + </screen> + + <para> + + You may, of course, specify any other location you prefer, + and may use the <option>--version-lib</option> option + if you would like to install version-specific directories + relative to the specified prefix. + + </para> + + <para> + + This can also be used to experiment with a newer + version of &SCons; than the one installed + in your system locations. + Of course, the location in which you install the + newer version of the &scons; script + (<filename>$HOME/bin</filename> in the above example) + must be configured in your &PATH; variable + before the directory containing + the system-installed version + of the &scons; script. + + </para> + + </section> + + </section> + + <!-- + + <section> + <title>Python Basics</title> + + <para> + + This section will provide a brief overview of + the Python programming language. + Skip this section if you are already familiar with Python + (or you're really intent on diving into &SCons; + and just picking up things as you go). + + </para> + + <para> + + Python has a lot of good + documentation freely available on-line + to help you get started. + The standard tutorial is available at XXX. + + + </para> + + <para> + + Python is very easy to pick up. + + </para> + + <para> + + Python variables must be assigned to before they can be referenced. + + </para> + + <para> + + Assignment is like most programming languages: + + x = 1 + 2 + z = 3 * x + + </para> + + <para> + + Function calls look like most language function calls: + + a = f(g) + + </para> + + <para> + + Define functions like so: + + def func(arg1, arg2): + return arg1 * arg 2 + + The number of parameters + + </para> + + <para> + + Strings can be enclosed in single quotes or double quotes, + backslashes are used to escape characters, + triple-quote syntax lets you include quotes and newlines, + raw strings begin with 'r'. + + </para> + + <para> + + Lists are enclosed in square brackets, + list items are separated by commas. + List references use square brackets and integer index values, + slice notation lets you select, delete or replace a range. + + </para> + + <para> + + Dictionaries (hashes) are enclosed in curly brackets, + : separates keys from values, + , separates items. + Dictionary values are referenced using square brackets. + + </para> + + <para> + + Access class attributes (including methods) using a '.'. + + </para> + + <para> + + if: statements look like + + elif: statements look like + + else: statements look like + + </para> + + <para> + + for: statements look like + + while: statements look like + + break statements look like + + continue statements look like + + </para> + + <para> + + pass + + </para> + + </section> + + --> diff --git a/doc/user/build-install.xml b/doc/user/build-install.xml new file mode 100644 index 0000000..ab289b1 --- /dev/null +++ b/doc/user/build-install.xml @@ -0,0 +1,719 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + This chapter will take you through the basic steps + of installing &SCons; on your system, + and building &SCons; if you don't have a + pre-built package available + (or simply prefer the flexibility of building it yourself). + Before that, however, this chapter will also describe the basic steps + involved in installing Python on your system, + in case that is necessary. + Fortunately, both &SCons; and Python + are very easy to install on almost any system, + and Python already comes installed on many systems. + + </para> + + <!-- + + <para> + + Lastly, this chapter also contains a section that + provides a brief overview of the Python programming language, + which is the language used to implement &SCons;, + and which forms the basis of the &SCons; configuration files. + Becoming familiar with some Python concepts will make it easier + to understand many of the examples in this User's Guide. + Nevertheless, it <emphasis>is</emphasis> possible + to configure simple &SCons; builds without knowing Python, + so you can skip this section if you + want to dive in and pick up things + by example- -or, of course, if you are + already familiar with Python. + + </para> + + --> + + <section> + <title>Installing Python</title> + + <para> + + Because &SCons; is written in Python, + you must obviously have Python installed on your system + to use &SCons;. + Before you try to install Python, + you should check to see if Python is already + available on your system by typing + <userinput>python -V</userinput> + (capital 'V') + or + <userinput>python --version</userinput> + at your system's command-line prompt. + + </para> + + <screen> + $ <userinput>python -V</userinput> + Python 2.5.1 + </screen> + + <para> + + And on a Windows system with Python installed: + + </para> + + <screen> + C:\><userinput>python -V</userinput> + Python 2.5.1 + </screen> + + <para> + + If Python is not installed on your system, + you will see an error message + stating something like "command not found" + (on UNIX or Linux) + or "'python' is not recognized + as an internal or external command, operable progam or batch file" + (on Windows). + In that case, you need to install Python + before you can install &SCons;. + + </para> + + <para> + + (Note that the <option>-V</option> option + was added to Python version 2.0, + so if your system only has an earlier version available + you may see an + <literal>"Unknown option: -V"</literal> + error message.) + + </para> + + <para> + + The standard location for information + about downloading and installing Python is + <ulink url="http://www.python.org/download/">http://www.python.org/download/</ulink>. + See that page for information about + how to download and install Python on your system. + + </para> + + <para> + + &SCons; will work with any version of Python from 1.5.2 or later. + If you need to install Python and have a choice, + we recommend using the most recent Python 2.5 version available. + Python 2.5 has significant improvements + that help speed up the performance of &SCons;. + + </para> + + </section> + + <section> + <title>Installing &SCons; From Pre-Built Packages</title> + + <para> + + &SCons; comes pre-packaged for installation on a number of systems, + including Linux and Windows systems. + You do not need to read this entire section, + you should need to read only the section + appropriate to the type of system you're running on. + + </para> + + <section> + <title>Installing &SCons; on Red Hat (and Other RPM-based) Linux Systems</title> + + <para> + + &SCons; comes in RPM (Red Hat Package Manager) format, + pre-built and ready to install on Red Hat Linux, + Fedora, + or any other Linux distribution that uses RPM. + Your distribution may + already have an &SCons; RPM built specifically for it; + many do, including SUSE, Mandrake and Fedora. + You can check for the availability of an &SCons; RPM + on your distribution's download servers, + or by consulting an RPM search site like + <ulink url="http://www.rpmfind.net/">http://www.rpmfind.net/</ulink> or + <ulink url="http://rpm.pbone.net/">http://rpm.pbone.net/</ulink>. + + </para> + + <para> + + If your distribution supports installation via + <application>yum</application>, + you should be able to install &SCons; by running: + + </para> + + <screen> + # <userinput>yum install scons</userinput> + </screen> + + <para> + + If your Linux distribution does not already have + a specific &SCons; RPM file, + you can download and install from the + generic RPM provided by the &SCons; project. + This will install the + SCons script(s) in <filename>/usr/bin</filename>, + and the SCons library modules in + <filename>/usr/lib/scons</filename>. + + </para> + + <para> + + To install from the command line, simply download the + appropriate <filename>.rpm</filename> file, + and then run: + + </para> + + <screen> + # <userinput>rpm -Uvh scons-1.2.0.d20091224-1.noarch.rpm</userinput> + </screen> + + <para> + + Or, you can use a graphical RPM package manager. + See your package manager application's documention + for specific instructions about + how to use it to install a downloaded RPM. + + </para> + + </section> + + <section> + <title>Installing &SCons; on Debian Linux Systems</title> + + <para> + + Debian Linux systems use a different package management + format that also makes it very easy to install &SCons;. + + </para> + + <para> + + If your system is connected to the Internet, + you can install the latest official Debian package + by running: + + </para> + + <screen> + # <userinput>apt-get install scons</userinput> + </screen> + + <!-- + + <para> + + Alternatively, + you can download the Debian package built + by the &SCons; project + and install it manually by running: + + </para> + + <screen> + # <userinput>db-XXX scons-*.deb</userinput> + </screen> + + --> + + </section> + + <section> + <title>Installing &SCons; on Windows Systems</title> + + <para> + + &SCons; provides a Windows installer + that makes installation extremely easy. + Download the <filename>scons-1.2.0.d20091224.win32.exe</filename> + file from the &SCons; download page at + <ulink url="http://www.scons.org/download.php">http://www.scons.org/download.php</ulink>. + Then all you need to do is execute the file + (usually by clicking on its icon in Windows Explorer). + These will take you through a small + sequence of windows that will install + &SCons; on your system. + + <!-- + Things are a little more complicated + if you are using the Cygwin version of Python. + This is because Cygwin + tries to make a Windows system look more + POSIX-like (or UNIX-like or Linux-like, if you prefer) + by having the Cygwin utilities, + including Cygwin Python, + interpret file name arguments on the command line + using the forward-slash (<filename>/</filename>) + as the directory separator, + instead of the normal Windows behavior of the + backslash (<filename>\</filename>) as the directory separator. + --> + + </para> + + <!-- + + <section> + <title>Installing &SCons; on Windows Systems Without Cygwin Python</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Installing &SCons; on Windows Systems With Cygwin Python</title> + + <para> + + XXX + + </para> + + </section> + + --> + + <!-- + + XXX - don't have the kinks worked out on how to + get these to display properly in all formats, + so comment them out for now. + + <screenshot> + <mediaobject> + <imageobject> + <imagedata fileref="SCons-win32-install-1.jpg" format="jpg" align="center"> + </imageobject> + </mediaobject> + </screenshot> + + <screenshot> + <mediaobject> + <imageobject> + <imagedata fileref="SCons-win32-install-2.jpg" format="jpg" align="center"> + </imageobject> + </mediaobject> + </screenshot> + + <screenshot> + <mediaobject> + <imageobject> + <imagedata fileref="SCons-win32-install-3.jpg" format="jpg" align="center"> + </imageobject> + </mediaobject> + </screenshot> + + <screenshot> + <mediaobject> + <imageobject> + <imagedata fileref="SCons-win32-install-4.jpg" format="jpg" align="center"> + </imageobject> + </mediaobject> + </screenshot> + + --> + + </section> + + </section> + + <section> + <title>Building and Installing &SCons; on Any System</title> + + <para> + + If a pre-built &SCons; package is not available for your system, + then you can still easily build and install &SCons; using the native + Python <filename>distutils</filename> package. + + </para> + + <para> + + The first step is to download either the + <filename>scons-1.2.0.d20091224.tar.gz</filename> + or <filename>scons-1.2.0.d20091224.zip</filename>, + which are available from the SCons download page at + <ulink url="http://www.scons.org/download.html">http://www.scons.org/download.html</ulink>. + + </para> + + <para> + + Unpack the archive you downloaded, + using a utility like <application>tar</application> + on Linux or UNIX, + or <application>WinZip</application> on Windows. + This will create a directory called + <filename>scons-1.2.0.d20091224</filename>, + usually in your local directory. + Then change your working directory to that directory + and install &SCons; by executing the following commands: + + </para> + + <screen> + # <userinput>cd scons-1.2.0.d20091224</userinput> + # <userinput>python setup.py install</userinput> + </screen> + + <para> + + This will build &SCons;, + install the &scons; script + in the default system scripts directory + (<filename>/usr/local/bin</filename> or + <filename>C:\Python25\Scripts</filename>), + and will install the &SCons; build engine + in an appropriate stand-alone library directory + (<filename>/usr/local/lib/scons</filename> or + <filename>C:\Python25\scons</filename>). + Because these are system directories, + you may need root (on Linux or UNIX) or Administrator (on Windows) + privileges to install &SCons; like this. + + </para> + + <!-- + + <section> + <title>Building and Installing &SCons; in the Standard Python Library Directories</title> + + <para> + + XXX + + </para> + + </section> + + --> + + <section> + <title>Building and Installing Multiple Versions of &SCons; Side-by-Side</title> + + <para> + + The &SCons; <filename>setup.py</filename> script + has some extensions that support + easy installation of multiple versions of &SCons; + in side-by-side locations. + This makes it easier to download and + experiment with different versions of &SCons; + before moving your official build process to a new version, + for example. + + </para> + + <para> + + To install &SCons; in a version-specific location, + add the <option>--version-lib</option> option + when you call <filename>setup.py</filename>: + + </para> + + <screen> + # <userinput>python setup.py install --version-lib</userinput> + </screen> + + <para> + + This will install the &SCons; build engine + in the + <filename>/usr/lib/scons-1.2.0.d20091224</filename> + or + <filename>C:\Python25\scons-1.2.0.d20091224</filename> + directory, for example. + + </para> + + <para> + + If you use the <option>--version-lib</option> option + the first time you install &SCons;, + you do not need to specify it each time you install + a new version. + The &SCons; <filename>setup.py</filename> script + will detect the version-specific directory name(s) + and assume you want to install all versions + in version-specific directories. + You can override that assumption in the future + by explicitly specifying the <option>--standalone-lib</option> option. + + </para> + + </section> + + <section> + <title>Installing &SCons; in Other Locations</title> + + <para> + + You can install &SCons; in locations other than + the default by specifying the <option>--prefix=</option> option: + + </para> + + <screen> + # <userinput>python setup.py install --prefix=/opt/scons</userinput> + </screen> + + <para> + + This would + install the <application>scons</application> script in + <filename>/opt/scons/bin</filename> + and the build engine in + <filename>/opt/scons/lib/scons</filename>, + + </para> + + <para> + + Note that you can specify both the <option>--prefix=</option> + and the <option>--version-lib</option> options + at the same type, + in which case <filename>setup.py</filename> + will install the build engine + in a version-specific directory + relative to the specified prefix. + Adding <option>--version-lib</option> to the + above example would install the build engine in + <filename>/opt/scons/lib/scons-1.2.0.d20091224</filename>. + + </para> + + </section> + + <section> + <title>Building and Installing &SCons; Without Administrative Privileges</title> + + <para> + + If you don't have the right privileges to install &SCons; + in a system location, + simply use the <literal>--prefix=</literal> option + to install it in a location of your choosing. + For example, + to install &SCons; in appropriate locations + relative to the user's <literal>$HOME</literal> directory, + the &scons; script in + <filename>$HOME/bin</filename> + and the build engine in + <filename>$HOME/lib/scons</filename>, + simply type: + + </para> + + <screen> + $ <userinput>python setup.py install --prefix=$HOME</userinput> + </screen> + + <para> + + You may, of course, specify any other location you prefer, + and may use the <option>--version-lib</option> option + if you would like to install version-specific directories + relative to the specified prefix. + + </para> + + <para> + + This can also be used to experiment with a newer + version of &SCons; than the one installed + in your system locations. + Of course, the location in which you install the + newer version of the &scons; script + (<filename>$HOME/bin</filename> in the above example) + must be configured in your &PATH; variable + before the directory containing + the system-installed version + of the &scons; script. + + </para> + + </section> + + </section> + + <!-- + + <section> + <title>Python Basics</title> + + <para> + + This section will provide a brief overview of + the Python programming language. + Skip this section if you are already familiar with Python + (or you're really intent on diving into &SCons; + and just picking up things as you go). + + </para> + + <para> + + Python has a lot of good + documentation freely available on-line + to help you get started. + The standard tutorial is available at XXX. + + + </para> + + <para> + + Python is very easy to pick up. + + </para> + + <para> + + Python variables must be assigned to before they can be referenced. + + </para> + + <para> + + Assignment is like most programming languages: + + x = 1 + 2 + z = 3 * x + + </para> + + <para> + + Function calls look like most language function calls: + + a = f(g) + + </para> + + <para> + + Define functions like so: + + def func(arg1, arg2): + return arg1 * arg 2 + + The number of parameters + + </para> + + <para> + + Strings can be enclosed in single quotes or double quotes, + backslashes are used to escape characters, + triple-quote syntax lets you include quotes and newlines, + raw strings begin with 'r'. + + </para> + + <para> + + Lists are enclosed in square brackets, + list items are separated by commas. + List references use square brackets and integer index values, + slice notation lets you select, delete or replace a range. + + </para> + + <para> + + Dictionaries (hashes) are enclosed in curly brackets, + : separates keys from values, + , separates items. + Dictionary values are referenced using square brackets. + + </para> + + <para> + + Access class attributes (including methods) using a '.'. + + </para> + + <para> + + if: statements look like + + elif: statements look like + + else: statements look like + + </para> + + <para> + + for: statements look like + + while: statements look like + + break statements look like + + continue statements look like + + </para> + + <para> + + pass + + </para> + + </section> + + --> diff --git a/doc/user/builders-built-in.in b/doc/user/builders-built-in.in new file mode 100644 index 0000000..245cb8c --- /dev/null +++ b/doc/user/builders-built-in.in @@ -0,0 +1,963 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; provides the ability to build a lot of different + types of files right "out of the box." + So far, we've been using &SCons;' ability to build + programs, objects and libraries to + illustrate much of the underlying functionality of &SCons; + This section will describe all of the different + types of files that you can build with &SCons;, + and the built-in &Builder; objects used to build them. + By default, all of the &Builder; objects in this section + can be built either with or without an explicit + construction environment. + + </para> + + <section> + <title>Programs: the &Program; Builder</title> + + <para> + + As we've seen, the &b-link-Program; Builder + is used to build an executable program. + The &source; argument is one or more + source-code files or object files, + and the ⌖ argument is the + name of the executable program name to be created. + For example: + + </para> + + <programlisting> + Program('prog', 'file1.o') + </programlisting> + + <para> + + Will create the &prog; + executable on a POSIX system, + the &prog_exe; executable on a Windows system. + + </para> + + <para> + + The target file's prefix and suffix may be omitted, + and the values from the + &cv-link-PROGPREFIX; + and + &cv-link-PROGSUFFIX; + construction variables + will be appended appropriately. + For example: + + </para> + + <programlisting> + env = Environment(PROGPREFIX='my', PROGSUFFIX='.xxx') + env.Program('prog', ['file1.o', 'file2.o']) + </programlisting> + + <para> + + Will create a program named + <filename>myprog.xxx</filename> + regardless of the system on which it is run. + + </para> + + <para> + + If you omit the ⌖, + the base of the first input + file name specified + becomes the base of the target + program created. + For example: + + </para> + + <programlisting> + Program(['hello.c', 'goodbye.c']) + </programlisting> + + <para> + + Will create the &hello; + executable on a POSIX system, + the &hello_exe; executable on a Windows system. + + </para> + + <para> + + Two construction variables control what libraries + will be linked with the resulting program. + The &cv-link-LIBS; variable is a list of the names of + libraries that will be linked into any programs, + and the &cv-link-LIBPATH; variables is a list of + directories that will be searched for + the specified libraries. + &SCons; will construct the right command-line + options for the running system. + For example: + + </para> + + <scons_example name="libs"> + <file name="SConstruct" printme="1"> + env = Environment(LIBS = ['foo1', 'foo2'], + LIBPATH = ['/usr/dir1', 'dir2']) + env.Program(['hello.c', 'goodbye.c']) + </file> + <file name="hello.c"> + int hello() { printf("Hello, world!\n"); } + </file> + <file name="goodbye.c"> + int goodbye() { printf("Goodbye, world!\n"); } + </file> + </scons_example> + + <para> + + Will execute as follows on a POSIX system: + + </para> + + <scons_output example="libs" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + And execute as follows on a Windows system: + + </para> + + <scons_output example="libs" os="win32"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + The &cv-LIBS; construction variable + is turned into command line options + by appending the &cv-link-LIBLINKPREFIX; and &cv-link-LIBLINKSUFFIX; + construction variables to the beginning and end, + respectively, of each specified library. + + </para> + + <para> + + The &cv-LIBPATH; construction variable + is turned into command line options + by appending the &cv-link-LIBDIRPREFIX; and &cv-link-LIBDIRSUFFIX; + construction variables to the beginning and end, + respectively, of each specified library. + + </para> + + <para> + + Other relevant construction variables + include those used by the &b-link-Object; + builders to affect how the + source files specified as input to the &t-Program; + builders are turned into object files; + see the next section. + + </para> + + <para> + + The command line used to control how a program is linked + is specified by the &cv-link-LINKCOM; construction variable. + By default, it uses the + &cv-link-LINK; construction variable + and the &cv-link-LINKFLAGS; construction variable. + + </para> + + </section> + + <section> + <title>Object-File Builders</title> + + <para> + + &SCons; provides separate Builder objects + to create static and shared object files. + The distinction becomes especially important when + archiving object files into different types of libraries. + + </para> + + <section> + <title>The &StaticObject; Builder</title> + + <para> + + The &b-link-StaticObject; Builder + is used to build an object file + suitable for static linking into a program, + or for inclusion in a static library. + The &source; argument is a single source-code file, + and the ⌖ argument is the + name of the static object file to be created. + For example: + + </para> + + <programlisting> + StaticObject('file', 'file.c') + </programlisting> + + <para> + + Will create the &file_o; + object file on a POSIX system, + the &file_obj; executable on a Windows system. + + </para> + + <para> + + The target file's prefix and suffix may be omitted, + and the values from the + &cv-link-OBJPREFIX; + and + &cv-link-OBJSUFFIX; + construction variables + will be appended appropriately. + For example: + + </para> + + <programlisting> + env = Environment(OBJPREFIX='my', OBJSUFFIX='.xxx') + env.StaticObject('file', 'file.c') + </programlisting> + + <para> + + Will create an object file named + <filename>myfile.xxx</filename> + regardless of the system on which it is run. + + </para> + + <para> + + If you omit the ⌖, + the base of the first input + file name specified + beomces the base of the name + of the static object file to be created. + For example: + + </para> + + <programlisting> + StaticObject('file.c') + </programlisting> + + <para> + + Will create the &file_o; + executable on a POSIX system, + the &file_obj; executable on a Windows system. + + </para> + + </section> + + <section> + <title>The &SharedObject; Builder</title> + + <para> + + The &b-link-SharedObject; Builder + is used to build an object file + suitable for shared linking into a program, + or for inclusion in a shared library. + The &source; argument is a single source-code file, + and the ⌖ argument is the + name of the shared object file to be created. + For example: + + </para> + + <programlisting> + SharedObject('file', 'file.c') + </programlisting> + + <para> + + Will create the &file_o; + object file on a POSIX system, + the &file_obj; executable on a Windows system. + + </para> + + <para> + + The target file's prefix and suffix may be omitted, + and the values from the + &cv-link-SHOBJPREFIX; + and + &cv-link-SHOBJSUFFIX; + construction variables + will be appended appropriately. + For example: + + </para> + + <programlisting> + env = Environment(SHOBJPREFIX='my', SHOBJSUFFIX='.xxx') + env.SharedObject('file', 'file.c') + </programlisting> + + <para> + + Will create an object file named + <filename>myfile.xxx</filename> + regardless of the system on which it is run. + + </para> + + <para> + + If you omit the ⌖, + the base of the first input + file name specified + becomes the base of the name + of the shared object file to be created. + For example: + + </para> + + <programlisting> + SharedObject('file.c') + </programlisting> + + <para> + + Will create the &file_o; + executable on a POSIX system, + the &file_obj; executable on a Windows system. + + </para> + + </section> + + <section> + <title>The &Object; Builder</title> + + <para> + + The &b-link-Object; Builder is a synonym for &b-link-StaticObject; + and is completely equivalent. + + </para> + + </section> + + </section> + + <section> + <title>Library Builders</title> + + <para> + + &SCons; provides separate Builder objects + to create static and shared libraries. + + </para> + + <section> + <title>The &StaticLibrary; Builder</title> + + <para> + + The &b-link-StaticLibrary; Builder + is used to create a library + suitable for static linking into a program. + The &source; argument is one or more + source-code files or object files, + and the ⌖ argument is the + name of the static library to be created. + For example: + + </para> + + <programlisting> + StaticLibrary('foo', ['file1.c', 'file2.c']) + </programlisting> + + <para> + + The target file's prefix and suffix may be omitted, + and the values from the + &cv-link-LIBPREFIX; + and + &cv-link-LIBSUFFIX; + construction variables + will be appended appropriately. + For example: + + </para> + + <programlisting> + env = Environment(LIBPREFIX='my', LIBSUFFIX='.xxx') + env.StaticLibrary('lib', ['file1.o', 'file2.o']) + </programlisting> + + <para> + + Will create an object file named + <filename>mylib.xxx</filename> + regardless of the system on which it is run. + + </para> + + <programlisting> + StaticLibrary('foo', ['file1.c', 'file2.c']) + </programlisting> + + <para> + + If you omit the ⌖, + the base of the first input + file name specified + becomes the base of the name of the static object file to be created. + For example: + + </para> + + <programlisting> + StaticLibrary(['file.c', 'another.c']) + </programlisting> + + <para> + + Will create the &libfile_a; + library on a POSIX system, + the &file_lib; library on a Windows system. + + </para> + + </section> + + <section> + <title>The &SharedLibrary; Builder</title> + + <para> + + The &b-link-SharedLibrary; Builder + is used to create a shared library + suitable for linking with a program. + The &source; argument is one or more + source-code files or object files, + and the ⌖ argument is the + name of the shared library to be created. + For example: + + </para> + + <programlisting> + SharedLibrary('foo', ['file1.c', 'file2.c']) + </programlisting> + + <para> + + The target file's prefix and suffix may be omitted, + and the values from the + &cv-link-SHLIBPREFIX; + and + &cv-link-SHLIBSUFFIX; + construction variables + will be appended appropriately. + For example: + + </para> + + <programlisting> + env = Environment(SHLIBPREFIX='my', SHLIBSUFFIX='.xxx') + env.SharedLibrary('shared', ['file1.o', 'file2.o']) + </programlisting> + + <para> + + Will create an object file named + <filename>myshared.xxx</filename> + regardless of the system on which it is run. + + </para> + + <programlisting> + SharedLibrary('foo', ['file1.c', 'file2.c']) + </programlisting> + + <para> + + If you omit the ⌖, + the base of the first input + file name specified + becomes the base of the name of the shared library to be created. + For example: + + </para> + + <programlisting> + SharedLibrary(['file.c', 'another.c']) + </programlisting> + + <para> + + Will create the &libfile_so; + library on a POSIX system, + the &file_dll; library on a Windows system. + + </para> + + </section> + + <section> + <title>The &Library; Builder</title> + + <para> + + The &b-link-Library; Builder is a synonym for &b-link-StaticLibrary; + and is completely equivalent. + + </para> + + </section> + + </section> + + <section> + <title>Pre-Compiled Headers: the &PCH; Builder</title> + + <para> + + XXX PCH() + + </para> + + </section> + + <section> + <title>Microsoft Visual C++ Resource Files: the &RES; Builder</title> + + <para> + + XXX RES() + + </para> + + </section> + + <section> + <title>Source Files</title> + + <para> + + By default + &SCons; supports two Builder objects + that know how to build source files + from other input files. + These are typically invoked "internally" + to turn files that need preprocessing into other source files. + + </para> + + <section> + <title>The &CFile; Builder</title> + + <para> + + XXX CFile() + + </para> + + <programlisting> + XXX CFile() programlisting + </programlisting> + + <screen> + XXX CFile() screen + </screen> + + </section> + + <section> + <title>The &CXXFile; Builder</title> + + <para> + + XXX CXXFILE() + + </para> + + <programlisting> + XXX CXXFILE() programlisting + </programlisting> + + <screen> + XXX CXXFILE() screen + </screen> + + </section> + + </section> + + <section> + <title>Documents</title> + + <para> + + &SCons; provides a number of Builder objects + for creating different types of documents. + + </para> + + <section> + <title>The &DVI; Builder</title> + + <para> + + XXX DVI() para + + </para> + + <programlisting> + XXX DVI() programlisting + </programlisting> + + <screen> + XXX DVI() screen + </screen> + + </section> + + <section> + <title>The &PDF; Builder</title> + + <para> + + XXX PDF() para + + </para> + + </section> + + <section> + <title>The &PostScript; Builder</title> + + <para> + + XXX PostScript() para + + </para> + + <programlisting> + XXX PostScript() programlisting + </programlisting> + + <screen> + XXX PostScript() screen + </screen> + + </section> + + </section> + + <section> + <title>Archives</title> + + <para> + + &SCons; provides Builder objects + for creating two different types of archive files. + + </para> + + <section> + <title>The &Tar; Builder</title> + + <para> + + The &b-link-Tar; Builder object uses the &tar; + utility to create archives of files + and/or directory trees: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Tar('out1.tar', ['file1', 'file2']) + env.Tar('out2', 'directory') + </file> + <file name="file1"> + file1 + </file> + <file name="file2"> + file2 + </file> + <file name="directory/file3"> + directory/file3 + </file> + </scons_example> + + <scons_output example="ex1" os="posix"> + <scons_output_command>scons -Q .</scons_output_command> + </scons_output> + + <para> + + One common requirement when creating a &tar; archive + is to create a compressed archive using the + <option>-z</option> option. + This is easily handled by specifying + the value of the &cv-link-TARFLAGS; variable + when you create the construction environment. + Note, however, that the <option>-c</option> used to + to instruct &tar; to create the archive + is part of the default value of &cv-TARFLAGS;, + so you need to set it both options: + + </para> + + <scons_example name="ex2"> + <file name="SConstruct" printme="1"> + env = Environment(TARFLAGS = '-c -z') + env.Tar('out.tar.gz', 'directory') + </file> + <file name="directory/file"> + directory/file + </file> + </scons_example> + + <scons_output example="ex2" os="posix"> + <scons_output_command>scons -Q .</scons_output_command> + </scons_output> + + <para> + + you may also wish to set the value of the + &cv-link-TARSUFFIX; construction variable + to your desired suffix for compress &tar; archives, + so that &SCons; can append it to the target file name + without your having to specify it explicitly: + + </para> + + <scons_example name="ex3"> + <file name="SConstruct" printme="1"> + env = Environment(TARFLAGS = '-c -z', + TARSUFFIX = '.tgz') + env.Tar('out', 'directory') + </file> + <file name="directory/file"> + directory/file + </file> + </scons_example> + + <scons_output example="ex3" os="posix"> + <scons_output_command>scons -Q .</scons_output_command> + </scons_output> + + </section> + + <section> + <title>The &Zip; Builder</title> + + <para> + + The &b-link-Zip; Builder object creates archives of files + and/or directory trees in the ZIP file format. + Python versions 1.6 or later + contain an internal &zipfile; module + that &SCons; will use. + In this case, given the following + &SConstruct; file: + + </para> + + <scons_example name="ex4"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Zip('out', ['file1', 'file2']) + </file> + <file name="file1"> + file1 + </file> + <file name="file2"> + file2 + </file> + </scons_example> + + <para> + + Your output will reflect the fact + that an internal Python function + is being used to create the output ZIP archive: + + </para> + + <scons_output example="ex4" os="posix"> + <scons_output_command>scons -Q .</scons_output_command> + </scons_output> + + <para> + + If you're using Python version 1.5.2 to run &SCons;, + then &SCons; will try to use an external + &zip; program as follows: + + </para> + + <screen> + % <userinput>scons -Q .</userinput> + zip /home/my/project/zip.out file1 file2 + </screen> + + </section> + + </section> + + <section> + <title>Java</title> + + <para> + + &SCons; provides Builder objects + for creating various types of Java output files. + + </para> + + <section> + <title>Building Class Files: the &Java; Builder</title> + + <para> + + The &b-link-Java; builder takes one or more input + <filename>.java</filename> files + and turns them into one or more + <filename>.class</filename> files + Unlike most builders, however, + the &Java; builder takes + target and source <emphasis>directories</emphasis>, + not files, as input. + + </para> + + <programlisting> + env = Environment() + env.Java(target = 'classes', source = 'src') + </programlisting> + + <para> + + The &Java; builder will then + search the specified source directory + tree for all <filename>.java</filename> files, + and pass any out-of-date + + </para> + + <screen> + XXX Java() screen + </screen> + + </section> + + <section> + <title>The &Jar; Builder</title> + + <para> + + XXX The &Jar; builder object + + </para> + + <programlisting> + env = Environment() + env.Java(target = 'classes', source = 'src') + env.Jar(target = '', source = 'classes') + </programlisting> + + <screen> + XXX Jar() screen + </screen> + + </section> + + <section> + <title>Building C header and stub files: the &JavaH; Builder</title> + + <para> + + XXX JavaH() para + + </para> + + <programlisting> + XXX JavaH() programlisting + </programlisting> + + <screen> + XXX JavaH() screen + </screen> + + </section> + + <section> + <title>Building RMI stub and skeleton class files: the &RMIC; Builder</title> + + <para> + + XXX RMIC() para + + </para> + + <programlisting> + XXX RMIC() programlisting + </programlisting> + + <screen> + XXX RMIC() screen + </screen> + + </section> + + </section> diff --git a/doc/user/builders-built-in.xml b/doc/user/builders-built-in.xml new file mode 100644 index 0000000..bee5b38 --- /dev/null +++ b/doc/user/builders-built-in.xml @@ -0,0 +1,949 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; provides the ability to build a lot of different + types of files right "out of the box." + So far, we've been using &SCons;' ability to build + programs, objects and libraries to + illustrate much of the underlying functionality of &SCons; + This section will describe all of the different + types of files that you can build with &SCons;, + and the built-in &Builder; objects used to build them. + By default, all of the &Builder; objects in this section + can be built either with or without an explicit + construction environment. + + </para> + + <section> + <title>Programs: the &Program; Builder</title> + + <para> + + As we've seen, the &b-link-Program; Builder + is used to build an executable program. + The &source; argument is one or more + source-code files or object files, + and the ⌖ argument is the + name of the executable program name to be created. + For example: + + </para> + + <programlisting> + Program('prog', 'file1.o') + </programlisting> + + <para> + + Will create the &prog; + executable on a POSIX system, + the &prog_exe; executable on a Windows system. + + </para> + + <para> + + The target file's prefix and suffix may be omitted, + and the values from the + &cv-link-PROGPREFIX; + and + &cv-link-PROGSUFFIX; + construction variables + will be appended appropriately. + For example: + + </para> + + <programlisting> + env = Environment(PROGPREFIX='my', PROGSUFFIX='.xxx') + env.Program('prog', ['file1.o', 'file2.o']) + </programlisting> + + <para> + + Will create a program named + <filename>myprog.xxx</filename> + regardless of the system on which it is run. + + </para> + + <para> + + If you omit the ⌖, + the base of the first input + file name specified + becomes the base of the target + program created. + For example: + + </para> + + <programlisting> + Program(['hello.c', 'goodbye.c']) + </programlisting> + + <para> + + Will create the &hello; + executable on a POSIX system, + the &hello_exe; executable on a Windows system. + + </para> + + <para> + + Two construction variables control what libraries + will be linked with the resulting program. + The &cv-link-LIBS; variable is a list of the names of + libraries that will be linked into any programs, + and the &cv-link-LIBPATH; variables is a list of + directories that will be searched for + the specified libraries. + &SCons; will construct the right command-line + options for the running system. + For example: + + </para> + + <programlisting> + env = Environment(LIBS = ['foo1', 'foo2'], + LIBPATH = ['/usr/dir1', 'dir2']) + env.Program(['hello.c', 'goodbye.c']) + </programlisting> + + <para> + + Will execute as follows on a POSIX system: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o goodbye.o -c goodbye.c + cc -o hello.o -c hello.c + cc -o hello hello.o goodbye.o -L/usr/dir1 -Ldir2 -lfoo1 -lfoo2 + </screen> + + <para> + + And execute as follows on a Windows system: + + </para> + + <screen> + C:\><userinput>scons -Q</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + cl /Fogoodbye.obj /c goodbye.c /nologo + cl /Fohello.obj /c hello.c /nologo + link /nologo /OUT:hello.exe /LIBPATH:\usr\dir1 /LIBPATH:dir2 foo1.lib foo2.lib hello.obj goodbye.obj + </screen> + + <para> + + The &cv-LIBS; construction variable + is turned into command line options + by appending the &cv-link-LIBLINKPREFIX; and &cv-link-LIBLINKSUFFIX; + construction variables to the beginning and end, + respectively, of each specified library. + + </para> + + <para> + + The &cv-LIBPATH; construction variable + is turned into command line options + by appending the &cv-link-LIBDIRPREFIX; and &cv-link-LIBDIRSUFFIX; + construction variables to the beginning and end, + respectively, of each specified library. + + </para> + + <para> + + Other relevant construction variables + include those used by the &b-link-Object; + builders to affect how the + source files specified as input to the &t-Program; + builders are turned into object files; + see the next section. + + </para> + + <para> + + The command line used to control how a program is linked + is specified by the &cv-link-LINKCOM; construction variable. + By default, it uses the + &cv-link-LINK; construction variable + and the &cv-link-LINKFLAGS; construction variable. + + </para> + + </section> + + <section> + <title>Object-File Builders</title> + + <para> + + &SCons; provides separate Builder objects + to create static and shared object files. + The distinction becomes especially important when + archiving object files into different types of libraries. + + </para> + + <section> + <title>The &StaticObject; Builder</title> + + <para> + + The &b-link-StaticObject; Builder + is used to build an object file + suitable for static linking into a program, + or for inclusion in a static library. + The &source; argument is a single source-code file, + and the ⌖ argument is the + name of the static object file to be created. + For example: + + </para> + + <programlisting> + StaticObject('file', 'file.c') + </programlisting> + + <para> + + Will create the &file_o; + object file on a POSIX system, + the &file_obj; executable on a Windows system. + + </para> + + <para> + + The target file's prefix and suffix may be omitted, + and the values from the + &cv-link-OBJPREFIX; + and + &cv-link-OBJSUFFIX; + construction variables + will be appended appropriately. + For example: + + </para> + + <programlisting> + env = Environment(OBJPREFIX='my', OBJSUFFIX='.xxx') + env.StaticObject('file', 'file.c') + </programlisting> + + <para> + + Will create an object file named + <filename>myfile.xxx</filename> + regardless of the system on which it is run. + + </para> + + <para> + + If you omit the ⌖, + the base of the first input + file name specified + beomces the base of the name + of the static object file to be created. + For example: + + </para> + + <programlisting> + StaticObject('file.c') + </programlisting> + + <para> + + Will create the &file_o; + executable on a POSIX system, + the &file_obj; executable on a Windows system. + + </para> + + </section> + + <section> + <title>The &SharedObject; Builder</title> + + <para> + + The &b-link-SharedObject; Builder + is used to build an object file + suitable for shared linking into a program, + or for inclusion in a shared library. + The &source; argument is a single source-code file, + and the ⌖ argument is the + name of the shared object file to be created. + For example: + + </para> + + <programlisting> + SharedObject('file', 'file.c') + </programlisting> + + <para> + + Will create the &file_o; + object file on a POSIX system, + the &file_obj; executable on a Windows system. + + </para> + + <para> + + The target file's prefix and suffix may be omitted, + and the values from the + &cv-link-SHOBJPREFIX; + and + &cv-link-SHOBJSUFFIX; + construction variables + will be appended appropriately. + For example: + + </para> + + <programlisting> + env = Environment(SHOBJPREFIX='my', SHOBJSUFFIX='.xxx') + env.SharedObject('file', 'file.c') + </programlisting> + + <para> + + Will create an object file named + <filename>myfile.xxx</filename> + regardless of the system on which it is run. + + </para> + + <para> + + If you omit the ⌖, + the base of the first input + file name specified + becomes the base of the name + of the shared object file to be created. + For example: + + </para> + + <programlisting> + SharedObject('file.c') + </programlisting> + + <para> + + Will create the &file_o; + executable on a POSIX system, + the &file_obj; executable on a Windows system. + + </para> + + </section> + + <section> + <title>The &Object; Builder</title> + + <para> + + The &b-link-Object; Builder is a synonym for &b-link-StaticObject; + and is completely equivalent. + + </para> + + </section> + + </section> + + <section> + <title>Library Builders</title> + + <para> + + &SCons; provides separate Builder objects + to create static and shared libraries. + + </para> + + <section> + <title>The &StaticLibrary; Builder</title> + + <para> + + The &b-link-StaticLibrary; Builder + is used to create a library + suitable for static linking into a program. + The &source; argument is one or more + source-code files or object files, + and the ⌖ argument is the + name of the static library to be created. + For example: + + </para> + + <programlisting> + StaticLibrary('foo', ['file1.c', 'file2.c']) + </programlisting> + + <para> + + The target file's prefix and suffix may be omitted, + and the values from the + &cv-link-LIBPREFIX; + and + &cv-link-LIBSUFFIX; + construction variables + will be appended appropriately. + For example: + + </para> + + <programlisting> + env = Environment(LIBPREFIX='my', LIBSUFFIX='.xxx') + env.StaticLibrary('lib', ['file1.o', 'file2.o']) + </programlisting> + + <para> + + Will create an object file named + <filename>mylib.xxx</filename> + regardless of the system on which it is run. + + </para> + + <programlisting> + StaticLibrary('foo', ['file1.c', 'file2.c']) + </programlisting> + + <para> + + If you omit the ⌖, + the base of the first input + file name specified + becomes the base of the name of the static object file to be created. + For example: + + </para> + + <programlisting> + StaticLibrary(['file.c', 'another.c']) + </programlisting> + + <para> + + Will create the &libfile_a; + library on a POSIX system, + the &file_lib; library on a Windows system. + + </para> + + </section> + + <section> + <title>The &SharedLibrary; Builder</title> + + <para> + + The &b-link-SharedLibrary; Builder + is used to create a shared library + suitable for linking with a program. + The &source; argument is one or more + source-code files or object files, + and the ⌖ argument is the + name of the shared library to be created. + For example: + + </para> + + <programlisting> + SharedLibrary('foo', ['file1.c', 'file2.c']) + </programlisting> + + <para> + + The target file's prefix and suffix may be omitted, + and the values from the + &cv-link-SHLIBPREFIX; + and + &cv-link-SHLIBSUFFIX; + construction variables + will be appended appropriately. + For example: + + </para> + + <programlisting> + env = Environment(SHLIBPREFIX='my', SHLIBSUFFIX='.xxx') + env.SharedLibrary('shared', ['file1.o', 'file2.o']) + </programlisting> + + <para> + + Will create an object file named + <filename>myshared.xxx</filename> + regardless of the system on which it is run. + + </para> + + <programlisting> + SharedLibrary('foo', ['file1.c', 'file2.c']) + </programlisting> + + <para> + + If you omit the ⌖, + the base of the first input + file name specified + becomes the base of the name of the shared library to be created. + For example: + + </para> + + <programlisting> + SharedLibrary(['file.c', 'another.c']) + </programlisting> + + <para> + + Will create the &libfile_so; + library on a POSIX system, + the &file_dll; library on a Windows system. + + </para> + + </section> + + <section> + <title>The &Library; Builder</title> + + <para> + + The &b-link-Library; Builder is a synonym for &b-link-StaticLibrary; + and is completely equivalent. + + </para> + + </section> + + </section> + + <section> + <title>Pre-Compiled Headers: the &PCH; Builder</title> + + <para> + + XXX PCH() + + </para> + + </section> + + <section> + <title>Microsoft Visual C++ Resource Files: the &RES; Builder</title> + + <para> + + XXX RES() + + </para> + + </section> + + <section> + <title>Source Files</title> + + <para> + + By default + &SCons; supports two Builder objects + that know how to build source files + from other input files. + These are typically invoked "internally" + to turn files that need preprocessing into other source files. + + </para> + + <section> + <title>The &CFile; Builder</title> + + <para> + + XXX CFile() + + </para> + + <programlisting> + XXX CFile() programlisting + </programlisting> + + <screen> + XXX CFile() screen + </screen> + + </section> + + <section> + <title>The &CXXFile; Builder</title> + + <para> + + XXX CXXFILE() + + </para> + + <programlisting> + XXX CXXFILE() programlisting + </programlisting> + + <screen> + XXX CXXFILE() screen + </screen> + + </section> + + </section> + + <section> + <title>Documents</title> + + <para> + + &SCons; provides a number of Builder objects + for creating different types of documents. + + </para> + + <section> + <title>The &DVI; Builder</title> + + <para> + + XXX DVI() para + + </para> + + <programlisting> + XXX DVI() programlisting + </programlisting> + + <screen> + XXX DVI() screen + </screen> + + </section> + + <section> + <title>The &PDF; Builder</title> + + <para> + + XXX PDF() para + + </para> + + </section> + + <section> + <title>The &PostScript; Builder</title> + + <para> + + XXX PostScript() para + + </para> + + <programlisting> + XXX PostScript() programlisting + </programlisting> + + <screen> + XXX PostScript() screen + </screen> + + </section> + + </section> + + <section> + <title>Archives</title> + + <para> + + &SCons; provides Builder objects + for creating two different types of archive files. + + </para> + + <section> + <title>The &Tar; Builder</title> + + <para> + + The &b-link-Tar; Builder object uses the &tar; + utility to create archives of files + and/or directory trees: + + </para> + + <programlisting> + env = Environment() + env.Tar('out1.tar', ['file1', 'file2']) + env.Tar('out2', 'directory') + </programlisting> + + <screen> + % <userinput>scons -Q .</userinput> + tar -c -f out1.tar file1 file2 + tar -c -f out2.tar directory + </screen> + + <para> + + One common requirement when creating a &tar; archive + is to create a compressed archive using the + <option>-z</option> option. + This is easily handled by specifying + the value of the &cv-link-TARFLAGS; variable + when you create the construction environment. + Note, however, that the <option>-c</option> used to + to instruct &tar; to create the archive + is part of the default value of &cv-TARFLAGS;, + so you need to set it both options: + + </para> + + <programlisting> + env = Environment(TARFLAGS = '-c -z') + env.Tar('out.tar.gz', 'directory') + </programlisting> + + <screen> + % <userinput>scons -Q .</userinput> + tar -c -z -f out.tar.gz directory + </screen> + + <para> + + you may also wish to set the value of the + &cv-link-TARSUFFIX; construction variable + to your desired suffix for compress &tar; archives, + so that &SCons; can append it to the target file name + without your having to specify it explicitly: + + </para> + + <programlisting> + env = Environment(TARFLAGS = '-c -z', + TARSUFFIX = '.tgz') + env.Tar('out', 'directory') + </programlisting> + + <screen> + % <userinput>scons -Q .</userinput> + tar -c -z -f out.tgz directory + </screen> + + </section> + + <section> + <title>The &Zip; Builder</title> + + <para> + + The &b-link-Zip; Builder object creates archives of files + and/or directory trees in the ZIP file format. + Python versions 1.6 or later + contain an internal &zipfile; module + that &SCons; will use. + In this case, given the following + &SConstruct; file: + + </para> + + <programlisting> + env = Environment() + env.Zip('out', ['file1', 'file2']) + </programlisting> + + <para> + + Your output will reflect the fact + that an internal Python function + is being used to create the output ZIP archive: + + </para> + + <screen> + % <userinput>scons -Q .</userinput> + zip(["out.zip"], ["file1", "file2"]) + </screen> + + <para> + + If you're using Python version 1.5.2 to run &SCons;, + then &SCons; will try to use an external + &zip; program as follows: + + </para> + + <screen> + % <userinput>scons -Q .</userinput> + zip /home/my/project/zip.out file1 file2 + </screen> + + </section> + + </section> + + <section> + <title>Java</title> + + <para> + + &SCons; provides Builder objects + for creating various types of Java output files. + + </para> + + <section> + <title>Building Class Files: the &Java; Builder</title> + + <para> + + The &b-link-Java; builder takes one or more input + <filename>.java</filename> files + and turns them into one or more + <filename>.class</filename> files + Unlike most builders, however, + the &Java; builder takes + target and source <emphasis>directories</emphasis>, + not files, as input. + + </para> + + <programlisting> + env = Environment() + env.Java(target = 'classes', source = 'src') + </programlisting> + + <para> + + The &Java; builder will then + search the specified source directory + tree for all <filename>.java</filename> files, + and pass any out-of-date + + </para> + + <screen> + XXX Java() screen + </screen> + + </section> + + <section> + <title>The &Jar; Builder</title> + + <para> + + XXX The &Jar; builder object + + </para> + + <programlisting> + env = Environment() + env.Java(target = 'classes', source = 'src') + env.Jar(target = '', source = 'classes') + </programlisting> + + <screen> + XXX Jar() screen + </screen> + + </section> + + <section> + <title>Building C header and stub files: the &JavaH; Builder</title> + + <para> + + XXX JavaH() para + + </para> + + <programlisting> + XXX JavaH() programlisting + </programlisting> + + <screen> + XXX JavaH() screen + </screen> + + </section> + + <section> + <title>Building RMI stub and skeleton class files: the &RMIC; Builder</title> + + <para> + + XXX RMIC() para + + </para> + + <programlisting> + XXX RMIC() programlisting + </programlisting> + + <screen> + XXX RMIC() screen + </screen> + + </section> + + </section> diff --git a/doc/user/builders-commands.in b/doc/user/builders-commands.in new file mode 100644 index 0000000..687d12d --- /dev/null +++ b/doc/user/builders-commands.in @@ -0,0 +1,156 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 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> + + Creating a &Builder; and attaching it to a &consenv; + allows for a lot of flexibility when you + want to re-use actions + to build multiple files of the same type. + This can, however, be cumbersome + if you only need to execute one specific command + to build a single file (or group of files). + For these situations, &SCons; supports a + &Command; &Builder; that arranges + for a specific action to be executed + to build a specific file or files. + This looks a lot like the other builders + (like &b-link-Program;, &b-link-Object;, etc.), + but takes as an additional argument + the command to be executed to build the file: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Command('foo.out', 'foo.in', "sed 's/x/y/' < $SOURCE > $TARGET") + </file> + <file name="foo.in"> + foo.in + </file> + </scons_example> + + <para> + + When executed, + &SCons; runs the specified command, + substituting &cv-link-SOURCE; and &cv-link-TARGET; + as expected: + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + This is often more convenient than + creating a &Builder; object + and adding it to the &cv-link-BUILDERS; variable + of a &consenv; + + </para> + + <para> + + Note that the action you specify to the + &Command; &Builder; can be any legal &SCons; &Action;, + such as a Python function: + + </para> + + <scons_example name="ex2"> + <file name="SConstruct" printme="1"> + env = Environment() + def build(target, source, env): + # Whatever it takes to build + return None + env.Command('foo.out', 'foo.in', build) + </file> + <file name="foo.in"> + foo.in + </file> + </scons_example> + + <para> + + Which executes as follows: + + </para> + + <scons_output example="ex2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Note that &cv-link-SOURCE; and &cv-link-TARGET; are expanded + in the source and target as well as of SCons 1.1, + so you can write: + + </para> + + <scons_example name="ex3"> + <file name="SConstruct" printme="1"> + env.Command('${SOURCE.basename}.out', 'foo.in', build) + </file> + </scons_example> + + + <para> + + which does the same thing as the previous example, but allows you + to avoid repeating yourself. + + </para> + diff --git a/doc/user/builders-commands.xml b/doc/user/builders-commands.xml new file mode 100644 index 0000000..111b1d2 --- /dev/null +++ b/doc/user/builders-commands.xml @@ -0,0 +1,146 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 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> + + Creating a &Builder; and attaching it to a &consenv; + allows for a lot of flexibility when you + want to re-use actions + to build multiple files of the same type. + This can, however, be cumbersome + if you only need to execute one specific command + to build a single file (or group of files). + For these situations, &SCons; supports a + &Command; &Builder; that arranges + for a specific action to be executed + to build a specific file or files. + This looks a lot like the other builders + (like &b-link-Program;, &b-link-Object;, etc.), + but takes as an additional argument + the command to be executed to build the file: + + </para> + + <programlisting> + env = Environment() + env.Command('foo.out', 'foo.in', "sed 's/x/y/' < $SOURCE > $TARGET") + </programlisting> + + <para> + + When executed, + &SCons; runs the specified command, + substituting &cv-link-SOURCE; and &cv-link-TARGET; + as expected: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + sed 's/x/y/' < foo.in > foo.out + </screen> + + <para> + + This is often more convenient than + creating a &Builder; object + and adding it to the &cv-link-BUILDERS; variable + of a &consenv; + + </para> + + <para> + + Note that the action you specify to the + &Command; &Builder; can be any legal &SCons; &Action;, + such as a Python function: + + </para> + + <programlisting> + env = Environment() + def build(target, source, env): + # Whatever it takes to build + return None + env.Command('foo.out', 'foo.in', build) + </programlisting> + + <para> + + Which executes as follows: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + build(["foo.out"], ["foo.in"]) + </screen> + + <para> + + Note that &cv-link-SOURCE; and &cv-link-TARGET; are expanded + in the source and target as well as of SCons 1.1, + so you can write: + + </para> + + <programlisting> + env.Command('${SOURCE.basename}.out', 'foo.in', build) + </programlisting> + + + <para> + + which does the same thing as the previous example, but allows you + to avoid repeating yourself. + + </para> + diff --git a/doc/user/builders-writing.in b/doc/user/builders-writing.in new file mode 100644 index 0000000..4f54d99 --- /dev/null +++ b/doc/user/builders-writing.in @@ -0,0 +1,1087 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 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> + + Although &SCons; provides many useful methods + for building common software products: + programs, libraries, documents. + you frequently want to be + able to build some other type of file + not supported directly by &SCons;. + Fortunately, &SCons; makes it very easy + to define your own &Builder; objects + for any custom file types you want to build. + (In fact, the &SCons; interfaces for creating + &Builder; objects are flexible enough and easy enough to use + that all of the the &SCons; built-in &Builder; objects + are created the mechanisms described in this section.) + + </para> + + <section> + <title>Writing Builders That Execute External Commands</title> + + <para> + + The simplest &Builder; to create is + one that executes an external command. + For example, if we want to build + an output file by running the contents + of the input file through a command named + <literal>foobuild</literal>, + creating that &Builder; might look like: + + </para> + + <programlisting> + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + </programlisting> + + <para> + + All the above line does is create a free-standing + &Builder; object. + The next section will show us how to actually use it. + + </para> + + </section> + + <section> + <title>Attaching a Builder to a &ConsEnv;</title> + + <para> + + A &Builder; object isn't useful + until it's attached to a &consenv; + so that we can call it to arrange + for files to be built. + This is done through the &cv-link-BUILDERS; + &consvar; in an environment. + The &cv-BUILDERS; variable is a Python dictionary + that maps the names by which you want to call + various &Builder; objects to the objects themselves. + For example, if we want to call the + &Builder; we just defined by the name + <function>Foo</function>, + our &SConstruct; file might look like: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct"> + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env = Environment(BUILDERS = {'Foo' : bld}) + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + env.Foo('file.foo', 'file.input') + </file> + <file name="file.input"> + file.input + </file> + <file name="foobuild" chmod="0755"> + cat + </file> + </scons_example> + + <sconstruct> + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env = Environment(BUILDERS = {'Foo' : bld}) + </sconstruct> + + <para> + + With the &Builder; attached to our &consenv; + with the name <function>Foo</function>, + we can now actually call it like so: + + </para> + + <programlisting> + env.Foo('file.foo', 'file.input') + </programlisting> + + <para> + + Then when we run &SCons; it looks like: + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Note, however, that the default &cv-BUILDERS; + variable in a &consenv; + comes with a default set of &Builder; objects + already defined: + &b-link-Program;, &b-link-Library;, etc. + And when we explicitly set the &cv-BUILDERS; variable + when we create the &consenv;, + the default &Builder;s are no longer part of + the environment: + + </para> + + <!-- + The ToolSurrogate stuff that's used to capture output initializes + SCons.Defaults.ConstructionEnvironment with its own list of TOOLS. + In this next example, we want to show the user that when they + set the BUILDERS explicitly, the call to env.Program() generates + an AttributeError. This won't happen with all of the default + ToolSurrogates in the default construction environment. To make the + AttributeError show up, we have to overwite the default construction + environment's TOOLS variable so Program() builder doesn't show up. + + We do this by executing a slightly different SConstruct file than the + one we print in the guide, with two extra statements at the front + that overwrite the TOOLS variable as described. Note that we have + to jam those statements on to the first line to keep the line number + in the generated error consistent with what the user will see in the + User's Guide. + --> + <scons_example name="ex2"> + <file name="SConstruct"> + import SCons.Defaults; SCons.Defaults.ConstructionEnvironment['TOOLS'] = {}; bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file.foo', 'file.input') + env.Program('hello.c') + </file> + <file name="SConstruct.printme" printme="1"> + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file.foo', 'file.input') + env.Program('hello.c') + </file> + <file name="file.input"> + file.input + </file> + <file name="hello.c"> + hello.c + </file> + </scons_example> + + <scons_output example="ex2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + To be able to use both our own defined &Builder; objects + and the default &Builder; objects in the same &consenv;, + you can either add to the &cv-BUILDERS; variable + using the &Append; function: + + </para> + + <scons_example name="ex3"> + <file name="SConstruct"> + env = Environment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env.Append(BUILDERS = {'Foo' : bld}) + env.Foo('file.foo', 'file.input') + env.Program('hello.c') + </file> + <file name="file.input"> + file.input + </file> + <file name="hello.c"> + hello.c + </file> + <file name="foobuild" chmod="0755"> + cat + </file> + </scons_example> + + <sconstruct> + env = Environment() + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env.Append(BUILDERS = {'Foo' : bld}) + env.Foo('file.foo', 'file.input') + env.Program('hello.c') + </sconstruct> + + <para> + + Or you can explicitly set the appropriately-named + key in the &cv-BUILDERS; dictionary: + + </para> + + <sconstruct> + env = Environment() + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env['BUILDERS']['Foo'] = bld + env.Foo('file.foo', 'file.input') + env.Program('hello.c') + </sconstruct> + + <para> + + Either way, the same &consenv; + can then use both the newly-defined + <function>Foo</function> &Builder; + and the default &b-link-Program; &Builder;: + + </para> + + <scons_output example="ex3"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Letting &SCons; Handle The File Suffixes</title> + + <para> + + By supplying additional information + when you create a &Builder;, + you can let &SCons; add appropriate file + suffixes to the target and/or the source file. + For example, rather than having to specify + explicitly that you want the <literal>Foo</literal> + &Builder; to build the <literal>file.foo</literal> + target file from the <literal>file.input</literal> source file, + you can give the <literal>.foo</literal> + and <literal>.input</literal> suffixes to the &Builder;, + making for more compact and readable calls to + the <literal>Foo</literal> &Builder;: + + </para> + + <scons_example name="ex4"> + <file name="SConstruct"> + bld = Builder(action = 'foobuild < $SOURCE > $TARGET', + suffix = '.foo', + src_suffix = '.input') + env = Environment(BUILDERS = {'Foo' : bld}) + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + env.Foo('file1') + env.Foo('file2') + </file> + <file name="file1.input"> + file1.input + </file> + <file name="file2.input"> + file2.input + </file> + <file name="foobuild" chmod="0755"> + cat + </file> + </scons_example> + + <sconstruct> + bld = Builder(action = 'foobuild < $SOURCE > $TARGET', + suffix = '.foo', + src_suffix = '.input') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file1') + env.Foo('file2') + </sconstruct> + + <scons_output example="ex4"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + You can also supply a <literal>prefix</literal> keyword argument + if it's appropriate to have &SCons; append a prefix + to the beginning of target file names. + + </para> + + </section> + + <section> + <title>Builders That Execute Python Functions</title> + + <para> + + In &SCons;, you don't have to call an external command + to build a file. + You can, instead, define a Python function + that a &Builder; object can invoke + to build your target file (or files). + Such a &buildfunc; definition looks like: + + </para> + + <programlisting> + def build_function(target, source, env): + # Code to build "target" from "source" + return None + </programlisting> + + <para> + + The arguments of a &buildfunc; are: + + </para> + + <variablelist> + + <varlistentry> + <term>target</term> + + <listitem> + <para> + + A list of Node objects representing + the target or targets to be + built by this builder function. + The file names of these target(s) + may be extracted using the Python &str; function. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>source</term> + + <listitem> + <para> + + A list of Node objects representing + the sources to be + used by this builder function to build the targets. + The file names of these source(s) + may be extracted using the Python &str; function. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>env</term> + + <listitem> + <para> + + The &consenv; used for building the target(s). + The builder function may use any of the + environment's construction variables + in any way to affect how it builds the targets. + + </para> + </listitem> + </varlistentry> + + </variablelist> + + <para> + + The builder function must + return a <literal>0</literal> or <literal>None</literal> value + if the target(s) are built successfully. + The builder function + may raise an exception + or return any non-zero value + to indicate that the build is unsuccessful, + + </para> + + <para> + + Once you've defined the Python function + that will build your target file, + defining a &Builder; object for it is as + simple as specifying the name of the function, + instead of an external command, + as the &Builder;'s + <literal>action</literal> + argument: + + </para> + + <scons_example name="ex5"> + <file name="SConstruct" printme="1"> + def build_function(target, source, env): + # Code to build "target" from "source" + return None + bld = Builder(action = build_function, + suffix = '.foo', + src_suffix = '.input') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file') + </file> + <file name="file.input"> + file.input + </file> + </scons_example> + + <para> + + And notice that the output changes slightly, + reflecting the fact that a Python function, + not an external command, + is now called to build the target file: + + </para> + + <scons_output example="ex5"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Builders That Create Actions Using a &Generator;</title> + + <para> + + &SCons; Builder objects can create an action "on the fly" + by using a function called a &generator;. + This provides a great deal of flexibility to + construct just the right list of commands + to build your target. + A &generator; looks like: + + </para> + + <programlisting> + def generate_actions(source, target, env, for_signature): + return 'foobuild < %s > %s' % (target[0], source[0]) + </programlisting> + + <para> + + The arguments of a &generator; are: + + </para> + + <variablelist> + + <varlistentry> + <term>source</term> + + <listitem> + <para> + + A list of Node objects representing + the sources to be built + by the command or other action + generated by this function. + The file names of these source(s) + may be extracted using the Python &str; function. + + </para> + </listitem> + + </varlistentry> + + <varlistentry> + <term>target</term> + + <listitem> + <para> + + A list of Node objects representing + the target or targets to be built + by the command or other action + generated by this function. + The file names of these target(s) + may be extracted using the Python &str; function. + + </para> + </listitem> + + </varlistentry> + + <varlistentry> + <term>env</term> + + <listitem> + <para> + + The &consenv; used for building the target(s). + The generator may use any of the + environment's construction variables + in any way to determine what command + or other action to return. + + </para> + </listitem> + + </varlistentry> + + <varlistentry> + <term>for_signature</term> + + <listitem> + <para> + + A flag that specifies whether the + generator is being called to contribute to a build signature, + as opposed to actually executing the command. + + <!-- XXX NEED MORE HERE, describe generators use in signatures --> + + </para> + </listitem> + + </varlistentry> + + </variablelist> + + <para> + + The &generator; must return a + command string or other action that will be used to + build the specified target(s) from the specified source(s). + + </para> + + <para> + + Once you've defined a &generator;, + you create a &Builder; to use it + by specifying the generator keyword argument + instead of <literal>action</literal>. + + </para> + + <scons_example name="ex6"> + <file name="SConstruct"> + def generate_actions(source, target, env, for_signature): + return 'foobuild < %s > %s' % (source[0], target[0]) + bld = Builder(generator = generate_actions, + suffix = '.foo', + src_suffix = '.input') + env = Environment(BUILDERS = {'Foo' : bld}) + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + env.Foo('file') + </file> + <file name="file.input"> + file.input + </file> + <file name="foobuild" chmod="0755"> + cat + </file> + </scons_example> + + <sconstruct> + def generate_actions(source, target, env, for_signature): + return 'foobuild < %s > %s' % (source[0], target[0]) + bld = Builder(generator = generate_actions, + suffix = '.foo', + src_suffix = '.input') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file') + </sconstruct> + + <scons_output example="ex6"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Note that it's illegal to specify both an + <literal>action</literal> + and a + <literal>generator</literal> + for a &Builder;. + + </para> + + </section> + + <section> + <title>Builders That Modify the Target or Source Lists Using an &Emitter;</title> + + <para> + + &SCons; supports the ability for a Builder to modify the + lists of target(s) from the specified source(s). + You do this by defining an &emitter; function + that takes as its arguments + the list of the targets passed to the builder, + the list of the sources passed to the builder, + and the construction environment. + The emitter function should return the modified + lists of targets that should be built + and sources from which the targets will be built. + + </para> + + <para> + + For example, suppose you want to define a Builder + that always calls a <filename>foobuild</filename> program, + and you want to automatically add + a new target file named + <filename>new_target</filename> + and a new source file named + <filename>new_source</filename> + whenever it's called. + The &SConstruct; file might look like this: + + </para> + + <scons_example name="ex7"> + <file name="SConstruct"> + def modify_targets(target, source, env): + target.append('new_target') + source.append('new_source') + return target, source + bld = Builder(action = 'foobuild $TARGETS - $SOURCES', + suffix = '.foo', + src_suffix = '.input', + emitter = modify_targets) + env = Environment(BUILDERS = {'Foo' : bld}) + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + env.Foo('file') + </file> + <file name="file.input"> + file.input + </file> + <file name="new_source"> + new_source + </file> + <file name="foobuild" chmod="0755"> + cat + </file> + </scons_example> + + <sconstruct> + def modify_targets(target, source, env): + target.append('new_target') + source.append('new_source') + return target, source + bld = Builder(action = 'foobuild $TARGETS - $SOURCES', + suffix = '.foo', + src_suffix = '.input', + emitter = modify_targets) + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file') + </sconstruct> + + <para> + + And would yield the following output: + + </para> + + <scons_output example="ex7"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + One very flexible thing that you can do is + use a construction variable to specify + different emitter functions for different + construction variable. + To do this, specify a string + containing a construction variable + expansion as the emitter when you call + the &Builder; function, + and set that construction variable to + the desired emitter function + in different construction environments: + + </para> + + <scons_example name="MY_EMITTER"> + + <file name="SConstruct" printme="1"> + bld = Builder(action = 'my_command $SOURCES > $TARGET', + suffix = '.foo', + src_suffix = '.input', + emitter = '$MY_EMITTER') + def modify1(target, source, env): + return target, source + ['modify1.in'] + def modify2(target, source, env): + return target, source + ['modify2.in'] + env1 = Environment(BUILDERS = {'Foo' : bld}, + MY_EMITTER = modify1) + env2 = Environment(BUILDERS = {'Foo' : bld}, + MY_EMITTER = modify2) + env1.Foo('file1') + env2.Foo('file2') + import os + env1['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd() + env2['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd() + </file> + <file name="file1.input"> + file1.input + </file> + <file name="file2.input"> + file2.input + </file> + <file name="modify1.in"> + modify1.input + </file> + <file name="modify2.in"> + modify2.input + </file> + <file name="my_command" chmod="0755"> + cat + </file> + </file> + + </scons_example> + + <sconstruct> + bld = Builder(action = 'my_command $SOURCES > $TARGET', + suffix = '.foo', + src_suffix = '.input', + emitter = '$MY_EMITTER') + def modify1(target, source, env): + return target, source + ['modify1.in'] + def modify2(target, source, env): + return target, source + ['modify2.in'] + env1 = Environment(BUILDERS = {'Foo' : bld}, + MY_EMITTER = modify1) + env2 = Environment(BUILDERS = {'Foo' : bld}, + MY_EMITTER = modify2) + env1.Foo('file1') + env2.Foo('file2') + </file> + </sconstruct> + + <para> + + In this example, the <filename>modify1.in</filename> + and <filename>modify2.in</filename> files + get added to the source lists + of the different commands: + + </para> + + <scons_output example="MY_EMITTER"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <!-- + + <section> + <title>target_factor=, source_factory=</title> + + </section> + + <section> + <title>target_scanner=, source_scanner=</title> + + </section> + + <section> + <title>multi=</title> + + </section> + + <section> + <title>single_source=</title> + + </section> + + <section> + <title>src_builder=</title> + + </section> + + <section> + <title>ensure_suffix=</title> + + </section> + + --> + + <section> + <title>Where To Put Your Custom Builders and Tools</title> + + <para> + + The <filename>site_scons</filename> directory gives you a place to + put Python modules you can import into your SConscripts + (site_scons), add-on tools that can integrate into &SCons; + (site_scons/site_tools), and a site_scons/site_init.py file that + gets read before any &SConstruct; or &SConscript;, allowing you to + change &SCons;'s default behavior. + + </para> + + <para> + + If you get a tool from somewhere (the &SCons; wiki or a third party, + for instance) and you'd like to use it in your project, the + <filename>site_scons</filename> dir is the simplest place to put it. + Tools come in two flavors; either a Python function that operates on + an &Environment; or a Python file containing two functions, exists() + and generate(). + + </para> + + <para> + + A single-function Tool can just be included in your + <filename>site_scons/site_init.py</filename> file where it will be + parsed and made available for use. For instance, you could have a + <filename>site_scons/site_init.py</filename> file like this: + + </para> + + <scons_example name="site1"> + <file name="site_scons/site_init.py" printme=1> + def TOOL_ADD_HEADER(env): + """A Tool to add a header from $HEADER to the source file""" + add_header = Builder(action=['echo "$HEADER" > $TARGET', + 'cat $SOURCE >> $TARGET']) + env.Append(BUILDERS = {'AddHeader' : add_header}) + env['HEADER'] = '' # set default value + </file> + <file name="SConstruct"> + env=Environment(tools=['default', TOOL_ADD_HEADER], HEADER="=====") + env.AddHeader('tgt', 'src') + </file> + <file name="src"> + hi there + </file> + </scons_example> + + <para> + + and a &SConstruct; like this: + + </para> + + <sconstruct> + # Use TOOL_ADD_HEADER from site_scons/site_init.py + env=Environment(tools=['default', TOOL_ADD_HEADER], HEADER="=====") + env.AddHeader('tgt', 'src') + </sconstruct> + + <para> + + The <function>TOOL_ADD_HEADER</function> tool method will be + called to add the <function>AddHeader</function> tool to the + environment. + + </para> + + <!-- + <scons_output example="site1" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + --> + + <para> + Similarly, a more full-fledged tool with + <function>exists()</function> and <function>generate()</function> + methods can be installed in + <filename>site_scons/site_tools/toolname.py</filename>. Since + <filename>site_scons/site_tools</filename> is automatically added + to the head of the tool search path, any tool found there will be + available to all environments. Furthermore, a tool found there + will override a built-in tool of the same name, so if you need to + change the behavior of a built-in tool, site_scons gives you the + hook you need. + </para> + + <para> + Many people have a library of utility Python functions they'd like + to include in &SConscript;s; just put that module in + <filename>site_scons/my_utils.py</filename> or any valid Python module name of your + choice. For instance you can do something like this in + <filename>site_scons/my_utils.py</filename> to add build_id and MakeWorkDir functions: + </para> + + <scons_example name="site2"> + <file name="site_scons/my_utils.py" printme=1> + from SCons.Script import * # for Execute and Mkdir + def build_id(): + """Return a build ID (stub version)""" + return "100" + def MakeWorkDir(workdir): + """Create the specified dir immediately""" + Execute(Mkdir(workdir)) + </file> + <file name="SConscript"> + import my_utils + MakeWorkDir('/tmp/work') + print "build_id=" + my_utils.build_id() + </file> + </scons_example> + + <para> + + And then in your &SConscript; or any sub-&SConscript; anywhere in + your build, you can import <filename>my_utils</filename> and use it: + + </para> + + <sconstruct> + import my_utils + print "build_id=" + my_utils.build_id() + my_utils.MakeWorkDir('/tmp/work') + </sconstruct> + + <para> + Note that although you can put this library in + <filename>site_scons/site_init.py</filename>, + it is no better there than <filename>site_scons/my_utils.py</filename> + since you still have to import that module into your &SConscript;. + Also note that in order to refer to objects in the SCons namespace + such as &Environment; or &Mkdir; or &Execute; in any file other + than a &SConstruct; or &SConscript; you always need to do + </para> + <sconstruct> + from SCons.Script import * + </sconstruct> + + <para> + This is true in modules in <filename>site_scons</filename> such as + <filename>site_scons/site_init.py</filename> as well. + </para> + + <para> + + If you have a machine-wide site dir you'd like to use instead of + <filename>./site_scons</filename>, use the + <literal>--site-dir</literal> option to point to your dir. + <filename>site_init.py</filename> and + <filename>site_tools</filename> will be located under that dir. + To avoid using a <filename>site_scons</filename> dir at all, even + if it exists, use the <literal>--no-site-dir</literal> option. + + </para> + + </section> + + + <!-- + + <section> + <title>Builders That Use Other Builders</title> + + <para> + + XXX para + + </para> + + <scons_example name="ex8"> + <file name="SConstruct" printme="1"> + env = Environment() + #env.SourceCode('.', env.BitKeeper('my_command')) + env.Program('hello.c') + </file> + <file name="hello.c"> + hello.c + </file> + </scons_example> + + <scons_output example="ex8"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + --> diff --git a/doc/user/builders-writing.xml b/doc/user/builders-writing.xml new file mode 100644 index 0000000..b05cce6 --- /dev/null +++ b/doc/user/builders-writing.xml @@ -0,0 +1,953 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 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> + + Although &SCons; provides many useful methods + for building common software products: + programs, libraries, documents. + you frequently want to be + able to build some other type of file + not supported directly by &SCons;. + Fortunately, &SCons; makes it very easy + to define your own &Builder; objects + for any custom file types you want to build. + (In fact, the &SCons; interfaces for creating + &Builder; objects are flexible enough and easy enough to use + that all of the the &SCons; built-in &Builder; objects + are created the mechanisms described in this section.) + + </para> + + <section> + <title>Writing Builders That Execute External Commands</title> + + <para> + + The simplest &Builder; to create is + one that executes an external command. + For example, if we want to build + an output file by running the contents + of the input file through a command named + <literal>foobuild</literal>, + creating that &Builder; might look like: + + </para> + + <programlisting> + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + </programlisting> + + <para> + + All the above line does is create a free-standing + &Builder; object. + The next section will show us how to actually use it. + + </para> + + </section> + + <section> + <title>Attaching a Builder to a &ConsEnv;</title> + + <para> + + A &Builder; object isn't useful + until it's attached to a &consenv; + so that we can call it to arrange + for files to be built. + This is done through the &cv-link-BUILDERS; + &consvar; in an environment. + The &cv-BUILDERS; variable is a Python dictionary + that maps the names by which you want to call + various &Builder; objects to the objects themselves. + For example, if we want to call the + &Builder; we just defined by the name + <function>Foo</function>, + our &SConstruct; file might look like: + + </para> + + + + <programlisting> + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env = Environment(BUILDERS = {'Foo' : bld}) + </programlisting> + + <para> + + With the &Builder; attached to our &consenv; + with the name <function>Foo</function>, + we can now actually call it like so: + + </para> + + <programlisting> + env.Foo('file.foo', 'file.input') + </programlisting> + + <para> + + Then when we run &SCons; it looks like: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + foobuild < file.input > file.foo + </screen> + + <para> + + Note, however, that the default &cv-BUILDERS; + variable in a &consenv; + comes with a default set of &Builder; objects + already defined: + &b-link-Program;, &b-link-Library;, etc. + And when we explicitly set the &cv-BUILDERS; variable + when we create the &consenv;, + the default &Builder;s are no longer part of + the environment: + + </para> + + <!-- + The ToolSurrogate stuff that's used to capture output initializes + SCons.Defaults.ConstructionEnvironment with its own list of TOOLS. + In this next example, we want to show the user that when they + set the BUILDERS explicitly, the call to env.Program() generates + an AttributeError. This won't happen with all of the default + ToolSurrogates in the default construction environment. To make the + AttributeError show up, we have to overwite the default construction + environment's TOOLS variable so Program() builder doesn't show up. + + We do this by executing a slightly different SConstruct file than the + one we print in the guide, with two extra statements at the front + that overwrite the TOOLS variable as described. Note that we have + to jam those statements on to the first line to keep the line number + in the generated error consistent with what the user will see in the + User's Guide. + --> + <programlisting> + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file.foo', 'file.input') + env.Program('hello.c') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + AttributeError: SConsEnvironment instance has no attribute 'Program': + File "/home/my/project/SConstruct", line 4: + env.Program('hello.c') + </screen> + + <para> + + To be able to use both our own defined &Builder; objects + and the default &Builder; objects in the same &consenv;, + you can either add to the &cv-BUILDERS; variable + using the &Append; function: + + </para> + + + + <programlisting> + env = Environment() + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env.Append(BUILDERS = {'Foo' : bld}) + env.Foo('file.foo', 'file.input') + env.Program('hello.c') + </programlisting> + + <para> + + Or you can explicitly set the appropriately-named + key in the &cv-BUILDERS; dictionary: + + </para> + + <programlisting> + env = Environment() + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env['BUILDERS']['Foo'] = bld + env.Foo('file.foo', 'file.input') + env.Program('hello.c') + </programlisting> + + <para> + + Either way, the same &consenv; + can then use both the newly-defined + <function>Foo</function> &Builder; + and the default &b-link-Program; &Builder;: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + foobuild < file.input > file.foo + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + </section> + + <section> + <title>Letting &SCons; Handle The File Suffixes</title> + + <para> + + By supplying additional information + when you create a &Builder;, + you can let &SCons; add appropriate file + suffixes to the target and/or the source file. + For example, rather than having to specify + explicitly that you want the <literal>Foo</literal> + &Builder; to build the <literal>file.foo</literal> + target file from the <literal>file.input</literal> source file, + you can give the <literal>.foo</literal> + and <literal>.input</literal> suffixes to the &Builder;, + making for more compact and readable calls to + the <literal>Foo</literal> &Builder;: + + </para> + + + + <programlisting> + bld = Builder(action = 'foobuild < $SOURCE > $TARGET', + suffix = '.foo', + src_suffix = '.input') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file1') + env.Foo('file2') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + foobuild < file1.input > file1.foo + foobuild < file2.input > file2.foo + </screen> + + <para> + + You can also supply a <literal>prefix</literal> keyword argument + if it's appropriate to have &SCons; append a prefix + to the beginning of target file names. + + </para> + + </section> + + <section> + <title>Builders That Execute Python Functions</title> + + <para> + + In &SCons;, you don't have to call an external command + to build a file. + You can, instead, define a Python function + that a &Builder; object can invoke + to build your target file (or files). + Such a &buildfunc; definition looks like: + + </para> + + <programlisting> + def build_function(target, source, env): + # Code to build "target" from "source" + return None + </programlisting> + + <para> + + The arguments of a &buildfunc; are: + + </para> + + <variablelist> + + <varlistentry> + <term>target</term> + + <listitem> + <para> + + A list of Node objects representing + the target or targets to be + built by this builder function. + The file names of these target(s) + may be extracted using the Python &str; function. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>source</term> + + <listitem> + <para> + + A list of Node objects representing + the sources to be + used by this builder function to build the targets. + The file names of these source(s) + may be extracted using the Python &str; function. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>env</term> + + <listitem> + <para> + + The &consenv; used for building the target(s). + The builder function may use any of the + environment's construction variables + in any way to affect how it builds the targets. + + </para> + </listitem> + </varlistentry> + + </variablelist> + + <para> + + The builder function must + return a <literal>0</literal> or <literal>None</literal> value + if the target(s) are built successfully. + The builder function + may raise an exception + or return any non-zero value + to indicate that the build is unsuccessful, + + </para> + + <para> + + Once you've defined the Python function + that will build your target file, + defining a &Builder; object for it is as + simple as specifying the name of the function, + instead of an external command, + as the &Builder;'s + <literal>action</literal> + argument: + + </para> + + <programlisting> + def build_function(target, source, env): + # Code to build "target" from "source" + return None + bld = Builder(action = build_function, + suffix = '.foo', + src_suffix = '.input') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file') + </programlisting> + + <para> + + And notice that the output changes slightly, + reflecting the fact that a Python function, + not an external command, + is now called to build the target file: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + build_function(["file.foo"], ["file.input"]) + </screen> + + </section> + + <section> + <title>Builders That Create Actions Using a &Generator;</title> + + <para> + + &SCons; Builder objects can create an action "on the fly" + by using a function called a &generator;. + This provides a great deal of flexibility to + construct just the right list of commands + to build your target. + A &generator; looks like: + + </para> + + <programlisting> + def generate_actions(source, target, env, for_signature): + return 'foobuild < %s > %s' % (target[0], source[0]) + </programlisting> + + <para> + + The arguments of a &generator; are: + + </para> + + <variablelist> + + <varlistentry> + <term>source</term> + + <listitem> + <para> + + A list of Node objects representing + the sources to be built + by the command or other action + generated by this function. + The file names of these source(s) + may be extracted using the Python &str; function. + + </para> + </listitem> + + </varlistentry> + + <varlistentry> + <term>target</term> + + <listitem> + <para> + + A list of Node objects representing + the target or targets to be built + by the command or other action + generated by this function. + The file names of these target(s) + may be extracted using the Python &str; function. + + </para> + </listitem> + + </varlistentry> + + <varlistentry> + <term>env</term> + + <listitem> + <para> + + The &consenv; used for building the target(s). + The generator may use any of the + environment's construction variables + in any way to determine what command + or other action to return. + + </para> + </listitem> + + </varlistentry> + + <varlistentry> + <term>for_signature</term> + + <listitem> + <para> + + A flag that specifies whether the + generator is being called to contribute to a build signature, + as opposed to actually executing the command. + + <!-- XXX NEED MORE HERE, describe generators use in signatures --> + + </para> + </listitem> + + </varlistentry> + + </variablelist> + + <para> + + The &generator; must return a + command string or other action that will be used to + build the specified target(s) from the specified source(s). + + </para> + + <para> + + Once you've defined a &generator;, + you create a &Builder; to use it + by specifying the generator keyword argument + instead of <literal>action</literal>. + + </para> + + + + <programlisting> + def generate_actions(source, target, env, for_signature): + return 'foobuild < %s > %s' % (source[0], target[0]) + bld = Builder(generator = generate_actions, + suffix = '.foo', + src_suffix = '.input') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + foobuild < file.input > file.foo + </screen> + + <para> + + Note that it's illegal to specify both an + <literal>action</literal> + and a + <literal>generator</literal> + for a &Builder;. + + </para> + + </section> + + <section> + <title>Builders That Modify the Target or Source Lists Using an &Emitter;</title> + + <para> + + &SCons; supports the ability for a Builder to modify the + lists of target(s) from the specified source(s). + You do this by defining an &emitter; function + that takes as its arguments + the list of the targets passed to the builder, + the list of the sources passed to the builder, + and the construction environment. + The emitter function should return the modified + lists of targets that should be built + and sources from which the targets will be built. + + </para> + + <para> + + For example, suppose you want to define a Builder + that always calls a <filename>foobuild</filename> program, + and you want to automatically add + a new target file named + <filename>new_target</filename> + and a new source file named + <filename>new_source</filename> + whenever it's called. + The &SConstruct; file might look like this: + + </para> + + + + <programlisting> + def modify_targets(target, source, env): + target.append('new_target') + source.append('new_source') + return target, source + bld = Builder(action = 'foobuild $TARGETS - $SOURCES', + suffix = '.foo', + src_suffix = '.input', + emitter = modify_targets) + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file') + </programlisting> + + <para> + + And would yield the following output: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + foobuild file.foo new_target - file.input new_source + </screen> + + <para> + + One very flexible thing that you can do is + use a construction variable to specify + different emitter functions for different + construction variable. + To do this, specify a string + containing a construction variable + expansion as the emitter when you call + the &Builder; function, + and set that construction variable to + the desired emitter function + in different construction environments: + + </para> + + <programlisting> + bld = Builder(action = 'my_command $SOURCES > $TARGET', + suffix = '.foo', + src_suffix = '.input', + emitter = '$MY_EMITTER') + def modify1(target, source, env): + return target, source + ['modify1.in'] + def modify2(target, source, env): + return target, source + ['modify2.in'] + env1 = Environment(BUILDERS = {'Foo' : bld}, + MY_EMITTER = modify1) + env2 = Environment(BUILDERS = {'Foo' : bld}, + MY_EMITTER = modify2) + env1.Foo('file1') + env2.Foo('file2') + import os + env1['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd() + env2['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd() + + + </programlisting> + + <programlisting> + bld = Builder(action = 'my_command $SOURCES > $TARGET', + suffix = '.foo', + src_suffix = '.input', + emitter = '$MY_EMITTER') + def modify1(target, source, env): + return target, source + ['modify1.in'] + def modify2(target, source, env): + return target, source + ['modify2.in'] + env1 = Environment(BUILDERS = {'Foo' : bld}, + MY_EMITTER = modify1) + env2 = Environment(BUILDERS = {'Foo' : bld}, + MY_EMITTER = modify2) + env1.Foo('file1') + env2.Foo('file2') + + </programlisting> + + <para> + + In this example, the <filename>modify1.in</filename> + and <filename>modify2.in</filename> files + get added to the source lists + of the different commands: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + my_command file1.input modify1.in > file1.foo + my_command file2.input modify2.in > file2.foo + </screen> + + </section> + + <!-- + + <section> + <title>target_factor=, source_factory=</title> + + </section> + + <section> + <title>target_scanner=, source_scanner=</title> + + </section> + + <section> + <title>multi=</title> + + </section> + + <section> + <title>single_source=</title> + + </section> + + <section> + <title>src_builder=</title> + + </section> + + <section> + <title>ensure_suffix=</title> + + </section> + + --> + + <section> + <title>Where To Put Your Custom Builders and Tools</title> + + <para> + + The <filename>site_scons</filename> directory gives you a place to + put Python modules you can import into your SConscripts + (site_scons), add-on tools that can integrate into &SCons; + (site_scons/site_tools), and a site_scons/site_init.py file that + gets read before any &SConstruct; or &SConscript;, allowing you to + change &SCons;'s default behavior. + + </para> + + <para> + + If you get a tool from somewhere (the &SCons; wiki or a third party, + for instance) and you'd like to use it in your project, the + <filename>site_scons</filename> dir is the simplest place to put it. + Tools come in two flavors; either a Python function that operates on + an &Environment; or a Python file containing two functions, exists() + and generate(). + + </para> + + <para> + + A single-function Tool can just be included in your + <filename>site_scons/site_init.py</filename> file where it will be + parsed and made available for use. For instance, you could have a + <filename>site_scons/site_init.py</filename> file like this: + + </para> + + <programlisting> + def TOOL_ADD_HEADER(env): + """A Tool to add a header from $HEADER to the source file""" + add_header = Builder(action=['echo "$HEADER" > $TARGET', + 'cat $SOURCE >> $TARGET']) + env.Append(BUILDERS = {'AddHeader' : add_header}) + env['HEADER'] = '' # set default value + </programlisting> + + <para> + + and a &SConstruct; like this: + + </para> + + <programlisting> + # Use TOOL_ADD_HEADER from site_scons/site_init.py + env=Environment(tools=['default', TOOL_ADD_HEADER], HEADER="=====") + env.AddHeader('tgt', 'src') + </programlisting> + + <para> + + The <function>TOOL_ADD_HEADER</function> tool method will be + called to add the <function>AddHeader</function> tool to the + environment. + + </para> + + <!-- + <scons_output example="site1" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + --> + + <para> + Similarly, a more full-fledged tool with + <function>exists()</function> and <function>generate()</function> + methods can be installed in + <filename>site_scons/site_tools/toolname.py</filename>. Since + <filename>site_scons/site_tools</filename> is automatically added + to the head of the tool search path, any tool found there will be + available to all environments. Furthermore, a tool found there + will override a built-in tool of the same name, so if you need to + change the behavior of a built-in tool, site_scons gives you the + hook you need. + </para> + + <para> + Many people have a library of utility Python functions they'd like + to include in &SConscript;s; just put that module in + <filename>site_scons/my_utils.py</filename> or any valid Python module name of your + choice. For instance you can do something like this in + <filename>site_scons/my_utils.py</filename> to add build_id and MakeWorkDir functions: + </para> + + <programlisting> + from SCons.Script import * # for Execute and Mkdir + def build_id(): + """Return a build ID (stub version)""" + return "100" + def MakeWorkDir(workdir): + """Create the specified dir immediately""" + Execute(Mkdir(workdir)) + </programlisting> + + <para> + + And then in your &SConscript; or any sub-&SConscript; anywhere in + your build, you can import <filename>my_utils</filename> and use it: + + </para> + + <programlisting> + import my_utils + print "build_id=" + my_utils.build_id() + my_utils.MakeWorkDir('/tmp/work') + </programlisting> + + <para> + Note that although you can put this library in + <filename>site_scons/site_init.py</filename>, + it is no better there than <filename>site_scons/my_utils.py</filename> + since you still have to import that module into your &SConscript;. + Also note that in order to refer to objects in the SCons namespace + such as &Environment; or &Mkdir; or &Execute; in any file other + than a &SConstruct; or &SConscript; you always need to do + </para> + <programlisting> + from SCons.Script import * + </programlisting> + + <para> + This is true in modules in <filename>site_scons</filename> such as + <filename>site_scons/site_init.py</filename> as well. + </para> + + <para> + + If you have a machine-wide site dir you'd like to use instead of + <filename>./site_scons</filename>, use the + <literal>--site-dir</literal> option to point to your dir. + <filename>site_init.py</filename> and + <filename>site_tools</filename> will be located under that dir. + To avoid using a <filename>site_scons</filename> dir at all, even + if it exists, use the <literal>--no-site-dir</literal> option. + + </para> + + </section> + + + <!-- + + <section> + <title>Builders That Use Other Builders</title> + + <para> + + XXX para + + </para> + + <scons_example name="ex8"> + <file name="SConstruct" printme="1"> + env = Environment() + #env.SourceCode('.', env.BitKeeper('my_command')) + env.Program('hello.c') + </file> + <file name="hello.c"> + hello.c + </file> + </scons_example> + + <scons_output example="ex8"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + --> diff --git a/doc/user/builders.in b/doc/user/builders.in new file mode 100644 index 0000000..a2f94ce --- /dev/null +++ b/doc/user/builders.in @@ -0,0 +1,57 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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. + +--> + +<!-- +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" +"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"> + +<refentry id="Command"> + +<refmeta> +<refentrytitle>Command</refentrytitle> +</refmeta> + +<methodsynopsis> + <methodname>env.Command</methodname> + <methodparam>foo</methodparam> + <methodparam>bar</methodparam> +</methodsynopsis> + +</refentry> +--> + +<para> + +This appendix contains descriptions of all of the +Builders that are <emphasis>potentially</emphasis> +available "out of the box" in this version of SCons. + +</para> + +<variablelist> + +&builders-gen; + +</variablelist> diff --git a/doc/user/builders.xml b/doc/user/builders.xml new file mode 100644 index 0000000..a2f94ce --- /dev/null +++ b/doc/user/builders.xml @@ -0,0 +1,57 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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. + +--> + +<!-- +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" +"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"> + +<refentry id="Command"> + +<refmeta> +<refentrytitle>Command</refentrytitle> +</refmeta> + +<methodsynopsis> + <methodname>env.Command</methodname> + <methodparam>foo</methodparam> + <methodparam>bar</methodparam> +</methodsynopsis> + +</refentry> +--> + +<para> + +This appendix contains descriptions of all of the +Builders that are <emphasis>potentially</emphasis> +available "out of the box" in this version of SCons. + +</para> + +<variablelist> + +&builders-gen; + +</variablelist> diff --git a/doc/user/caching.in b/doc/user/caching.in new file mode 100644 index 0000000..31b1103 --- /dev/null +++ b/doc/user/caching.in @@ -0,0 +1,502 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + On multi-developer software projects, + you can sometimes speed up every developer's builds a lot by + allowing them to share the derived files that they build. + &SCons; makes this easy, as well as reliable. + + </para> + + <section> + <title>Specifying the Shared Cache Directory</title> + + <para> + + To enable sharing of derived files, + use the &CacheDir; function + in any &SConscript; file: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct"> + env = Environment() + env.Program('hello.c') + CacheDir('cache') + </file> + <file name="hello.c"> + hello.c + </file> + <directory name="cache"> + </directory> + <file name="not_used" printme="1"> + CacheDir('/usr/local/build_cache') + </file> + </scons_example> + + <para> + + Note that the directory you specify must already exist + and be readable and writable by all developers + who will be sharing derived files. + It should also be in some central location + that all builds will be able to access. + In environments where developers are using separate systems + (like individual workstations) for builds, + this directory would typically be + on a shared or NFS-mounted file system. + + </para> + + <para> + + Here's what happens: + When a build has a &CacheDir; specified, + every time a file is built, + it is stored in the shared cache directory + along with its MD5 build signature. + <footnote> + <para> + Actually, the MD5 signature is used as the name of the file + in the shared cache directory in which the contents are stored. + </para> + </footnote> + On subsequent builds, + before an action is invoked to build a file, + &SCons; will check the shared cache directory + to see if a file with the exact same build + signature already exists. + If so, the derived file will not be built locally, + but will be copied into the local build directory + from the shared cache directory, + like so: + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q -c</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Note that the &CacheDir; feature still calculates + MD5 build sigantures for the shared cache file names + even if you configure &SCons; to use timestamps + to decide if files are up to date. + (See the <xref linkend="chap-depends"></xref> + chapter for information about the &Decider; function.) + Consequently, using &CacheDir; may reduce or eliminate any + potential performance improvements + from using timestamps for up-to-date decisions. + + </para> + + </section> + + <section> + <title>Keeping Build Output Consistent</title> + + <para> + + One potential drawback to using a shared cache + is that the output printed by &SCons; + can be inconsistent from invocation to invocation, + because any given file may be rebuilt one time + and retrieved from the shared cache the next time. + This can make analyzing build output more difficult, + especially for automated scripts that + expect consistent output each time. + + </para> + + <para> + + If, however, you use the <literal>--cache-show</literal> option, + &SCons; will print the command line that it + <emphasis>would</emphasis> have executed + to build the file, + even when it is retrieving the file from the shared cache. + This makes the build output consistent + every time the build is run: + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q -c</scons_output_command> + <scons_output_command>scons -Q --cache-show</scons_output_command> + </scons_output> + + <para> + + The trade-off, of course, is that you no longer + know whether or not &SCons; + has retrieved a derived file from cache + or has rebuilt it locally. + + </para> + + </section> + + <section> + <title>Not Using the Shared Cache for Specific Files</title> + + <para> + + You may want to disable caching for certain + specific files in your configuration. + For example, if you only want to put + executable files in a central cache, + but not the intermediate object files, + you can use the &NoCache; + function to specify that the + object files should not be cached: + + </para> + + <scons_example name="ex-NoCache"> + <file name="SConstruct" printme="1"> + env = Environment() + obj = env.Object('hello.c') + env.Program('hello.c') + CacheDir('cache') + NoCache('hello.o') + </file> + <file name="hello.c"> + hello.c + </file> + <directory name="cache"> + </directory> + </scons_example> + + <para> + + Then when you run &scons; after cleaning + the built targets, + it will recompile the object file locally + (since it doesn't exist in the shared cache directory), + but still realize that the shared cache directory + contains an up-to-date executable program + that can be retrieved instead of re-linking: + + </para> + + <!-- + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q -c</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q -c</userinput> + Removed hello.o + Removed hello + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + Retrieved `hello' from cache + </screen> + + </section> + + <section> + <title>Disabling the Shared Cache</title> + + <para> + + Retrieving an already-built file + from the shared cache + is usually a significant time-savings + over rebuilding the file, + but how much of a savings + (or even whether it saves time at all) + can depend a great deal on your + system or network configuration. + For example, retrieving cached files + from a busy server over a busy network + might end up being slower than + rebuilding the files locally. + + </para> + + <para> + + In these cases, you can specify + the <literal>--cache-disable</literal> + command-line option to tell &SCons; + to not retrieve already-built files from the + shared cache directory: + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q -c</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q -c</scons_output_command> + <scons_output_command>scons -Q --cache-disable</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Populating a Shared Cache With Already-Built Files</title> + + <para> + + Sometimes, you may have one or more derived files + already built in your local build tree + that you wish to make available to other people doing builds. + For example, you may find it more effective to perform + integration builds with the cache disabled + (per the previous section) + and only populate the shared cache directory + with the built files after the integration build + has completed successfully. + This way, the cache will only get filled up + with derived files that are part of a complete, successful build + not with files that might be later overwritten + while you debug integration problems. + + </para> + + <para> + + In this case, you can use the + the <literal>--cache-force</literal> option + to tell &SCons; to put all derived files in the cache, + even if the files already exist in your local tree + from having been built by a previous invocation: + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q --cache-disable</scons_output_command> + <scons_output_command>scons -Q -c</scons_output_command> + <scons_output_command>scons -Q --cache-disable</scons_output_command> + <scons_output_command>scons -Q --cache-force</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Notice how the above sample run + demonstrates that the <literal>--cache-disable</literal> + option avoids putting the built + <filename>hello.o</filename> + and + <filename>hello</filename> files in the cache, + but after using the <literal>--cache-force</literal> option, + the files have been put in the cache + for the next invocation to retrieve. + + </para> + + </section> + + <section> + <title>Minimizing Cache Contention: the <literal>--random</literal> Option</title> + + <para> + + If you allow multiple builds to update the + shared cache directory simultaneously, + two builds that occur at the same time + can sometimes start "racing" + with one another to build the same files + in the same order. + If, for example, + you are linking multiple files into an executable program: + + </para> + + <scons_example name="ex-random"> + <file name="SConstruct" printme="1"> + Program('prog', + ['f1.c', 'f2.c', 'f3.c', 'f4.c', 'f5.c']) + </file> + <file name="f1.c">f1.c</file> + <file name="f2.c">f2.c</file> + <file name="f3.c">f3.c</file> + <file name="f4.c">f4.c</file> + <file name="f5.c">f5.c</file> + <file name="f6.c">f6.c</file> + </scons_example> + + <para> + + &SCons; will normally build the input object files + on which the program depends in their normal, sorted order: + + </para> + + <scons_output example="ex-random"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + But if two such builds take place simultaneously, + they may each look in the cache at nearly the same + time and both decide that <filename>f1.o</filename> + must be rebuilt and pushed into the shared cache directory, + then both decide that <filename>f2.o</filename> + must be rebuilt (and pushed into the shared cache directory), + then both decide that <filename>f3.o</filename> + must be rebuilt... + This won't cause any actual build problems--both + builds will succeed, + generate correct output files, + and populate the cache--but + it does represent wasted effort. + + </para> + + <para> + + To alleviate such contention for the cache, + you can use the <literal>--random</literal> command-line option + to tell &SCons; to build dependencies + in a random order: + + </para> + + <!-- + + The following <screen> output was generated by this: + + <scons_output example="ex-random"> + <scons_output_command>scons -Q - -random</scons_output_command> + </scons_output> + + We captured it directly here to guarantee a "random" order, + guarding against the potential for - -random to happen + to return things in the original sorted order. + + --> + + <screen> + % <userinput>scons -Q --random</userinput> + cc -o f3.o -c f3.c + cc -o f1.o -c f1.c + cc -o f5.o -c f5.c + cc -o f2.o -c f2.c + cc -o f4.o -c f4.c + cc -o prog f1.o f2.o f3.o f4.o f5.o + </screen> + + <para> + + Multiple builds using the <literal>--random</literal> option + will usually build their dependencies in different, + random orders, + which minimizes the chances for a lot of + contention for same-named files + in the shared cache directory. + Multiple simultaneous builds might still race to try to build + the same target file on occasion, + but long sequences of inefficient contention + should be rare. + + </para> + + <para> + + Note, of course, + the <literal>--random</literal> option + will cause the output that &SCons; prints + to be inconsistent from invocation to invocation, + which may be an issue when + trying to compare output from different build runs. + + </para> + + <para> + + If you want to make sure dependencies will be built + in a random order without having to specify + the <literal>--random</literal> on very command line, + you can use the &SetOption; function to + set the <literal>random</literal> option + within any &SConscript; file: + + </para> + + <scons_example name="ex-random"> + <file name="SConstruct" printme="1"> + SetOption('random', 1) + Program('prog', + ['f1.c', 'f2.c', 'f3.c', 'f4.c', 'f5.c']) + </file> + <file name="f1.c">f1.c</file> + <file name="f2.c">f2.c</file> + <file name="f3.c">f3.c</file> + <file name="f4.c">f4.c</file> + <file name="f5.c">f5.c</file> + <file name="f6.c">f6.c</file> + </scons_example> + + </section> + + <!-- + + <section> + <title>Troubleshooting Shared Caching: the &cache-debug; Option</title> + + <para> + + XXX describe the - - cache-debug option + XXX maybe point to the troubleshooting appendix? + + </para> + + </section> + + --> + + <!-- + + <section> + + <para> + + XXX describe CacheDir management: monitoring, deleting, etc. + + </para> + + </section> + + --> diff --git a/doc/user/caching.xml b/doc/user/caching.xml new file mode 100644 index 0000000..073539c --- /dev/null +++ b/doc/user/caching.xml @@ -0,0 +1,506 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + On multi-developer software projects, + you can sometimes speed up every developer's builds a lot by + allowing them to share the derived files that they build. + &SCons; makes this easy, as well as reliable. + + </para> + + <section> + <title>Specifying the Shared Cache Directory</title> + + <para> + + To enable sharing of derived files, + use the &CacheDir; function + in any &SConscript; file: + + </para> + + <programlisting> + CacheDir('/usr/local/build_cache') + </programlisting> + + <para> + + Note that the directory you specify must already exist + and be readable and writable by all developers + who will be sharing derived files. + It should also be in some central location + that all builds will be able to access. + In environments where developers are using separate systems + (like individual workstations) for builds, + this directory would typically be + on a shared or NFS-mounted file system. + + </para> + + <para> + + Here's what happens: + When a build has a &CacheDir; specified, + every time a file is built, + it is stored in the shared cache directory + along with its MD5 build signature. + <footnote> + <para> + Actually, the MD5 signature is used as the name of the file + in the shared cache directory in which the contents are stored. + </para> + </footnote> + On subsequent builds, + before an action is invoked to build a file, + &SCons; will check the shared cache directory + to see if a file with the exact same build + signature already exists. + If so, the derived file will not be built locally, + but will be copied into the local build directory + from the shared cache directory, + like so: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q -c</userinput> + Removed hello.o + Removed hello + % <userinput>scons -Q</userinput> + Retrieved `hello.o' from cache + Retrieved `hello' from cache + </screen> + + <para> + + Note that the &CacheDir; feature still calculates + MD5 build sigantures for the shared cache file names + even if you configure &SCons; to use timestamps + to decide if files are up to date. + (See the <xref linkend="chap-depends"></xref> + chapter for information about the &Decider; function.) + Consequently, using &CacheDir; may reduce or eliminate any + potential performance improvements + from using timestamps for up-to-date decisions. + + </para> + + </section> + + <section> + <title>Keeping Build Output Consistent</title> + + <para> + + One potential drawback to using a shared cache + is that the output printed by &SCons; + can be inconsistent from invocation to invocation, + because any given file may be rebuilt one time + and retrieved from the shared cache the next time. + This can make analyzing build output more difficult, + especially for automated scripts that + expect consistent output each time. + + </para> + + <para> + + If, however, you use the <literal>--cache-show</literal> option, + &SCons; will print the command line that it + <emphasis>would</emphasis> have executed + to build the file, + even when it is retrieving the file from the shared cache. + This makes the build output consistent + every time the build is run: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q -c</userinput> + Removed hello.o + Removed hello + % <userinput>scons -Q --cache-show</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + <para> + + The trade-off, of course, is that you no longer + know whether or not &SCons; + has retrieved a derived file from cache + or has rebuilt it locally. + + </para> + + </section> + + <section> + <title>Not Using the Shared Cache for Specific Files</title> + + <para> + + You may want to disable caching for certain + specific files in your configuration. + For example, if you only want to put + executable files in a central cache, + but not the intermediate object files, + you can use the &NoCache; + function to specify that the + object files should not be cached: + + </para> + + <programlisting> + env = Environment() + obj = env.Object('hello.c') + env.Program('hello.c') + CacheDir('cache') + NoCache('hello.o') + </programlisting> + + <para> + + Then when you run &scons; after cleaning + the built targets, + it will recompile the object file locally + (since it doesn't exist in the shared cache directory), + but still realize that the shared cache directory + contains an up-to-date executable program + that can be retrieved instead of re-linking: + + </para> + + <!-- + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q -c</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q -c</userinput> + Removed hello.o + Removed hello + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + Retrieved `hello' from cache + </screen> + + </section> + + <section> + <title>Disabling the Shared Cache</title> + + <para> + + Retrieving an already-built file + from the shared cache + is usually a significant time-savings + over rebuilding the file, + but how much of a savings + (or even whether it saves time at all) + can depend a great deal on your + system or network configuration. + For example, retrieving cached files + from a busy server over a busy network + might end up being slower than + rebuilding the files locally. + + </para> + + <para> + + In these cases, you can specify + the <literal>--cache-disable</literal> + command-line option to tell &SCons; + to not retrieve already-built files from the + shared cache directory: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q -c</userinput> + Removed hello.o + Removed hello + % <userinput>scons -Q</userinput> + Retrieved `hello.o' from cache + Retrieved `hello' from cache + % <userinput>scons -Q -c</userinput> + Removed hello.o + Removed hello + % <userinput>scons -Q --cache-disable</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + </section> + + <section> + <title>Populating a Shared Cache With Already-Built Files</title> + + <para> + + Sometimes, you may have one or more derived files + already built in your local build tree + that you wish to make available to other people doing builds. + For example, you may find it more effective to perform + integration builds with the cache disabled + (per the previous section) + and only populate the shared cache directory + with the built files after the integration build + has completed successfully. + This way, the cache will only get filled up + with derived files that are part of a complete, successful build + not with files that might be later overwritten + while you debug integration problems. + + </para> + + <para> + + In this case, you can use the + the <literal>--cache-force</literal> option + to tell &SCons; to put all derived files in the cache, + even if the files already exist in your local tree + from having been built by a previous invocation: + + </para> + + <screen> + % <userinput>scons -Q --cache-disable</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q -c</userinput> + Removed hello.o + Removed hello + % <userinput>scons -Q --cache-disable</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q --cache-force</userinput> + scons: `.' is up to date. + % <userinput>scons -Q</userinput> + scons: `.' is up to date. + </screen> + + <para> + + Notice how the above sample run + demonstrates that the <literal>--cache-disable</literal> + option avoids putting the built + <filename>hello.o</filename> + and + <filename>hello</filename> files in the cache, + but after using the <literal>--cache-force</literal> option, + the files have been put in the cache + for the next invocation to retrieve. + + </para> + + </section> + + <section> + <title>Minimizing Cache Contention: the <literal>--random</literal> Option</title> + + <para> + + If you allow multiple builds to update the + shared cache directory simultaneously, + two builds that occur at the same time + can sometimes start "racing" + with one another to build the same files + in the same order. + If, for example, + you are linking multiple files into an executable program: + + </para> + + <programlisting> + Program('prog', + ['f1.c', 'f2.c', 'f3.c', 'f4.c', 'f5.c']) + </programlisting> + + <para> + + &SCons; will normally build the input object files + on which the program depends in their normal, sorted order: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o f1.o -c f1.c + cc -o f2.o -c f2.c + cc -o f3.o -c f3.c + cc -o f4.o -c f4.c + cc -o f5.o -c f5.c + cc -o prog f1.o f2.o f3.o f4.o f5.o + </screen> + + <para> + + But if two such builds take place simultaneously, + they may each look in the cache at nearly the same + time and both decide that <filename>f1.o</filename> + must be rebuilt and pushed into the shared cache directory, + then both decide that <filename>f2.o</filename> + must be rebuilt (and pushed into the shared cache directory), + then both decide that <filename>f3.o</filename> + must be rebuilt... + This won't cause any actual build problems--both + builds will succeed, + generate correct output files, + and populate the cache--but + it does represent wasted effort. + + </para> + + <para> + + To alleviate such contention for the cache, + you can use the <literal>--random</literal> command-line option + to tell &SCons; to build dependencies + in a random order: + + </para> + + <!-- + + The following <screen> output was generated by this: + + <scons_output example="ex-random"> + <scons_output_command>scons -Q - -random</scons_output_command> + </scons_output> + + We captured it directly here to guarantee a "random" order, + guarding against the potential for - -random to happen + to return things in the original sorted order. + + --> + + <screen> + % <userinput>scons -Q --random</userinput> + cc -o f3.o -c f3.c + cc -o f1.o -c f1.c + cc -o f5.o -c f5.c + cc -o f2.o -c f2.c + cc -o f4.o -c f4.c + cc -o prog f1.o f2.o f3.o f4.o f5.o + </screen> + + <para> + + Multiple builds using the <literal>--random</literal> option + will usually build their dependencies in different, + random orders, + which minimizes the chances for a lot of + contention for same-named files + in the shared cache directory. + Multiple simultaneous builds might still race to try to build + the same target file on occasion, + but long sequences of inefficient contention + should be rare. + + </para> + + <para> + + Note, of course, + the <literal>--random</literal> option + will cause the output that &SCons; prints + to be inconsistent from invocation to invocation, + which may be an issue when + trying to compare output from different build runs. + + </para> + + <para> + + If you want to make sure dependencies will be built + in a random order without having to specify + the <literal>--random</literal> on very command line, + you can use the &SetOption; function to + set the <literal>random</literal> option + within any &SConscript; file: + + </para> + + <programlisting> + Program('prog', + ['f1.c', 'f2.c', 'f3.c', 'f4.c', 'f5.c']) + + SetOption('random', 1) + Program('prog', + ['f1.c', 'f2.c', 'f3.c', 'f4.c', 'f5.c']) + </programlisting> + + </section> + + <!-- + + <section> + <title>Troubleshooting Shared Caching: the &cache-debug; Option</title> + + <para> + + XXX describe the - - cache-debug option + XXX maybe point to the troubleshooting appendix? + + </para> + + </section> + + --> + + <!-- + + <section> + + <para> + + XXX describe CacheDir management: monitoring, deleting, etc. + + </para> + + </section> + + --> diff --git a/doc/user/command-line.in b/doc/user/command-line.in new file mode 100644 index 0000000..686146e --- /dev/null +++ b/doc/user/command-line.in @@ -0,0 +1,2327 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; provides a number of ways + for the writer of the &SConscript; files + to give the users who will run &SCons; + a great deal of control over the build execution. + The arguments that the user can specify on + the command line are broken down into three types: + + </para> + + <variablelist> + + <varlistentry> + <term>Options</term> + + <listitem> + <para> + + Command-line options always begin with + one or two <literal>-</literal> (hyphen) characters. + &SCons; provides ways for you to examine + and set options values from within your &SConscript; files, + as well as the ability to define your own + custom options. + See <xref linkend="sect-command-line-options"></xref>, below. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Variables</term> + + <listitem> + <para> + + Any command-line argument containing an <literal>=</literal> + (equal sign) is considered a variable setting with the form + <varname>variable</varname>=<varname>value</varname> + &SCons; provides direct access to + all of the command-line variable settings, + the ability to apply command-line variable settings + to construction environments, + and functions for configuring + specific types of variables + (Boolean values, path names, etc.) + with automatic validation of the user's specified values. + See <xref linkend="sect-command-line-variables"></xref>, below. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Targets</term> + + <listitem> + <para> + + Any command-line argument that is not an option + or a variable setting + (does not begin with a hyphen + and does not contain an equal sign) + is considered a target that the user + (presumably) wants &SCons; to build. + A list of Node objects representing + the target or targets to build. + &SCons; provides access to the list of specified targets, + as well as ways to set the default list of targets + from within the &SConscript; files. + See <xref linkend="sect-command-line-targets"></xref>, below. + + </para> + </listitem> + </varlistentry> + + </variablelist> + + <section id="sect-command-line-options"> + <title>Command-Line Options</title> + + <para> + + &SCons; has many <emphasis>command-line options</emphasis> + that control its behavior. + A &SCons; <emphasis>command-line option</emphasis> + always begins with one or two <literal>-</literal> (hyphen) + characters. + + </para> + + <section> + <title>Not Having to Specify Command-Line Options Each Time: the &SCONSFLAGS; Environment Variable</title> + + <para> + + Users may find themselves supplying + the same command-line options every time + they run &SCons;. + For example, you might find it saves time + to specify a value of <literal>-j 2</literal> + to have &SCons; run up to two build commands in parallel. + To avoid having to type <literal>-j 2</literal> by hand + every time, + you can set the external environment variable + &SCONSFLAGS; to a string containing + command-line options that you want &SCons; to use. + + </para> + + <para> + + If, for example, + you're using a POSIX shell that's + compatible with the Bourne shell, + and you always want &SCons; to use the + <literal>-Q</literal> option, + you can set the &SCONSFLAGS; + environment as follows: + + </para> + + <scons_example name="SCONSFLAGS"> + <file name="SConstruct"> + def b(target, source, env): + pass + def s(target, source, env): + return " ... [build output] ..." + a = Action(b, strfunction = s) + env = Environment(BUILDERS = {'A' : Builder(action=a)}) + env.A('foo.out', 'foo.in') + </file> + <file name="foo.in"> + foo.in + </file> + </scons_example> + + <scons_output example="SCONSFLAGS"> + <scons_output_command>scons</scons_output_command> + <scons_output_command>export SCONSFLAGS="-Q"</scons_output_command> + <scons_output_command environment="SCONSFLAGS=-Q">scons</scons_output_command> + </scons_output> + + <para> + + Users of &csh;-style shells on POSIX systems + can set the &SCONSFLAGS; environment as follows: + + </para> + + <screen> + $ <userinput>setenv SCONSFLAGS "-Q"</userinput> + </screen> + + <para> + + Windows users may typically want to set the + &SCONSFLAGS; in the appropriate tab of the + <literal>System Properties</literal> window. + + </para> + + </section> + + <section> + <title>Getting Values Set by Command-Line Options: the &GetOption; Function</title> + + <para> + + &SCons; provides the &GetOption; function + to get the values set by the various command-line options. + One common use of this is to check whether or not + the <literal>-h</literal> or <literal>--help</literal> option + has been specified. + Normally, &SCons; does not print its help text + until after it has read all of the &SConscript; files, + because it's possible that help text has been added + by some subsidiary &SConscript; file deep in the + source tree hierarchy. + Of course, reading all of the &SConscript; files + takes extra time. + + </para> + + <para> + + If you know that your configuration does not define + any additional help text in subsidiary &SConscript; files, + you can speed up the command-line help available to users + by using the &GetOption; function to load the + subsidiary &SConscript; files only if the + the user has <emphasis>not</emphasis> specified + the <literal>-h</literal> or <literal>--help</literal> option, + like so: + + </para> + + <sconstruct) + if not GetOption('help'): + SConscript('src/SConscript', export='env') + </sconstruct> + + <para> + + In general, the string that you pass to the + &GetOption; function to fetch the value of a command-line + option setting is the same as the "most common" long option name + (beginning with two hyphen characters), + although there are some exceptions. + The list of &SCons; command-line options + and the &GetOption; strings for fetching them, + are available in the + <xref linkend="sect-command-line-option-strings"></xref> section, + below. + + </para> + + </section> + + <section> + <title>Setting Values of Command-Line Options: the &SetOption; Function</title> + + <para> + + You can also set the values of &SCons; + command-line options from within the &SConscript; files + by using the &SetOption; function. + The strings that you use to set the values of &SCons; + command-line options are available in the + <xref linkend="sect-command-line-option-strings"></xref> section, + below. + + </para> + + <para> + + One use of the &SetOption; function is to + specify a value for the <literal>-j</literal> + or <literal>--jobs</literal> option, + so that users get the improved performance + of a parallel build without having to specify the option by hand. + A complicating factor is that a good value + for the <literal>-j</literal> option is + somewhat system-dependent. + One rough guideline is that the more processors + your system has, + the higher you want to set the + <literal>-j</literal> value, + in order to take advantage of the number of CPUs. + + </para> + + <para> + + For example, suppose the administrators + of your development systems + have standardized on setting a + <varname>NUM_CPU</varname> environment variable + to the number of processors on each system. + A little bit of Python code + to access the environment variable + and the &SetOption; function + provide the right level of flexibility: + + </para> + + <scons_example name="SetOption"> + <file name="SConstruct" printme="1"> + import os + num_cpu = int(os.environ.get('NUM_CPU', 2)) + SetOption('num_jobs', num_cpu) + print "running with -j", GetOption('num_jobs') + </file> + <file name="foo.in"> + foo.in + </file> + </scons_example> + + <para> + + The above snippet of code + sets the value of the <literal>--jobs</literal> option + to the value specified in the + <varname>$NUM_CPU</varname> environment variable. + (This is one of the exception cases + where the string is spelled differently from + the from command-line option. + The string for fetching or setting the <literal>--jobs</literal> + value is <literal>num_jobs</literal> + for historical reasons.) + The code in this example prints the <literal>num_jobs</literal> + value for illustrative purposes. + It uses a default value of <literal>2</literal> + to provide some minimal parallelism even on + single-processor systems: + + </para> + + <scons_output example="SetOption"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + But if the <varname>$NUM_CPU</varname> + environment variable is set, + then we use that for the default number of jobs: + + </para> + + <scons_output example="SetOption"> + <scons_output_command>export NUM_CPU="4"</scons_output_command> + <scons_output_command environment="NUM_CPU=4">scons -Q</scons_output_command> + </scons_output> + + <para> + + But any explicit + <literal>-j</literal> or <literal>--jobs</literal> + value the user specifies an the command line is used first, + regardless of whether or not + the <varname>$NUM_CPU</varname> environment + variable is set: + + </para> + + <scons_output example="SetOption"> + <scons_output_command>scons -Q -j 7</scons_output_command> + <scons_output_command>export NUM_CPU="4"</scons_output_command> + <scons_output_command environment="NUM_CPU=4">scons -Q -j 3</scons_output_command> + </scons_output> + + </section> + + <section id="sect-command-line-option-strings"> + <title>Strings for Getting or Setting Values of &SCons; Command-Line Options</title> + + <para> + + The strings that you can pass to the &GetOption; + and &SetOption; functions usually correspond to the + first long-form option name + (beginning with two hyphen characters: <literal>--</literal>), + after replacing any remaining hyphen characters + with underscores. + + </para> + + <para> + + The full list of strings and the variables they + correspond to is as follows: + + </para> + + <informaltable> + <tgroup cols="2" align="left"> + + <thead> + + <row> + <entry>String for &GetOption; and &SetOption;</entry> + <entry>Command-Line Option(s)</entry> + </row> + + </thead> + + <tbody> + + <row> + <entry><literal>cache_debug</literal></entry> + <entry><option>--cache-debug</option></entry> + </row> + + <row> + <entry><literal>cache_disable</literal></entry> + <entry><option>--cache-disable</option></entry> + </row> + + <row> + <entry><literal>cache_force</literal></entry> + <entry><option>--cache-force</option></entry> + </row> + + <row> + <entry><literal>cache_show</literal></entry> + <entry><option>--cache-show</option></entry> + </row> + + <row> + <entry><literal>clean</literal></entry> + <entry><option>-c</option>, + <option>--clean</option>, + <option>--remove</option></entry> + </row> + + <row> + <entry><literal>config</literal></entry> + <entry><option>--config</option></entry> + </row> + + <row> + <entry><literal>directory</literal></entry> + <entry><option>-C</option>, + <option>--directory</option></entry> + </row> + + <row> + <entry><literal>diskcheck</literal></entry> + <entry><option>--diskcheck</option></entry> + </row> + + <row> + <entry><literal>duplicate</literal></entry> + <entry><option>--duplicate</option></entry> + </row> + + <row> + <entry><literal>file</literal></entry> + <entry><option>-f</option>, + <option>--file</option>, + <option>--makefile </option>, + <option>--sconstruct</option></entry> + </row> + + <row> + <entry><literal>help</literal></entry> + <entry><option>-h</option>, + <option>--help</option></entry> + </row> + + <row> + <entry><literal>ignore_errors</literal></entry> + <entry><option>--ignore-errors</option></entry> + </row> + + <row> + <entry><literal>implicit_cache</literal></entry> + <entry><option>--implicit-cache</option></entry> + </row> + + <row> + <entry><literal>implicit_deps_changed</literal></entry> + <entry><option>--implicit-deps-changed</option></entry> + </row> + + <row> + <entry><literal>implicit_deps_unchanged</literal></entry> + <entry><option>--implicit-deps-unchanged</option></entry> + </row> + + <row> + <entry><literal>interactive</literal></entry> + <entry><option>--interact</option>, + <option>--interactive</option></entry> + </row> + + <row> + <entry><literal>keep_going</literal></entry> + <entry><option>-k</option>, + <option>--keep-going</option></entry> + </row> + + <row> + <entry><literal>max_drift</literal></entry> + <entry><option>--max-drift</option></entry> + </row> + + <row> + <entry><literal>no_exec</literal></entry> + <entry><option>-n</option>, + <option>--no-exec</option>, + <option>--just-print</option>, + <option>--dry-run</option>, + <option>--recon</option></entry> + </row> + + <row> + <entry><literal>no_site_dir</literal></entry> + <entry><option>--no-site-dir</option></entry> + </row> + + <row> + <entry><literal>num_jobs</literal></entry> + <entry><option>-j</option>, + <option>--jobs</option></entry> + </row> + + <row> + <entry><literal>profile_file</literal></entry> + <entry><option>--profile</option></entry> + </row> + + <row> + <entry><literal>question</literal></entry> + <entry><option>-q</option>, + <option>--question</option></entry> + </row> + + <row> + <entry><literal>random</literal></entry> + <entry><option>--random</option></entry> + </row> + + <row> + <entry><literal>repository</literal></entry> + <entry><option>-Y</option>, + <option>--repository</option>, + <option>--srcdir</option></entry> + </row> + + <row> + <entry><literal>silent</literal></entry> + <entry><option>-s</option>, + <option>--silent</option>, + <option>--quiet</option></entry> + </row> + + <row> + <entry><literal>site_dir</literal></entry> + <entry><option>--site-dir</option></entry> + </row> + + <row> + <entry><literal>stack_size</literal></entry> + <entry><option>--stack-size</option></entry> + </row> + + <row> + <entry><literal>taskmastertrace_file</literal></entry> + <entry><option>--taskmastertrace</option></entry> + </row> + + <row> + <entry><literal>warn</literal></entry> + <entry><option>--warn</option> <option>--warning</option></entry> + </row> + + </tbody> + + </tgroup> + </informaltable> + + </section> + + <section> + <title>Adding Custom Command-Line Options: the &AddOption; Function</title> + + <para> + + &SCons; also allows you to define your own + command-line options with the &AddOption; function. + The &AddOption; function takes the same arguments + as the <function>optparse.add_option</function> function + from the standard Python library. + <footnote> + <para> + The &AddOption; function is, + in fact, implemented using a subclass + of the <classname>optparse.OptionParser</classname>. + </para> + </footnote> + Once you have added a custom command-line option + with the &AddOption; function, + the value of the option (if any) is immediately available + using the standard &GetOption; function. + (The value can also be set using &SetOption;, + although that's not very useful in practice + because a default value can be specified in + directly in the &AddOption; call.) + + </para> + + <para> + + One useful example of using this functionality + is to provide a <option>--prefix</option> for users: + + </para> + + <scons_example name="AddOption"> + <file name="SConstruct" printme="1"> + AddOption('--prefix', + dest='prefix', + type='string', + nargs=1, + action='store', + metavar='DIR', + help='installation prefix') + + env = Environment(PREFIX = GetOption('prefix')) + + installed_foo = env.Install('$PREFIX/usr/bin', 'foo.in') + Default(installed_foo) + </file> + <file name="foo.in"> + foo.in + </file> + </scons_example> + + <para> + + The above code uses the &GetOption; function + to set the <varname>$PREFIX</varname> + construction variable to any + value that the user specifies with a command-line + option of <literal>--prefix</literal>. + Because <varname>$PREFIX</varname> + will expand to a null string if it's not initialized, + running &SCons; without the + option of <literal>--prefix</literal> + will install the file in the + <filename>/usr/bin/</filename> directory: + + </para> + + <scons_output example="AddOption"> + <scons_output_command>scons -Q -n</scons_output_command> + </scons_output> + + <para> + + But specifying <literal>--prefix=/tmp/install</literal> + on the command line causes the file to be installed in the + <filename>/tmp/install/usr/bin/</filename> directory: + + </para> + + <scons_output example="AddOption"> + <scons_output_command>scons -Q -n --prefix=/tmp/install</scons_output_command> + </scons_output> + + </section> + + </section> + + <section id="sect-command-line-variables"> + <title>Command-Line <varname>variable</varname>=<varname>value</varname> Build Variables</title> + + <para> + + You may want to control various aspects + of your build by allowing the user + to specify <varname>variable</varname>=<varname>value</varname> + values on the command line. + For example, suppose you + want users to be able to + build a debug version of a program + by running &SCons; as follows: + + </para> + + <screen> + % <userinput>scons -Q debug=1</userinput> + </screen> + + <para> + + &SCons; provides an &ARGUMENTS; dictionary + that stores all of the + <varname>variable</varname>=<varname>value</varname> + assignments from the command line. + This allows you to modify + aspects of your build in response + to specifications on the command line. + (Note that unless you want to require + that users <emphasis>always</emphasis> + specify a variable, + you probably want to use + the Python + <literal>ARGUMENTS.get()</literal> function, + which allows you to specify a default value + to be used if there is no specification + on the command line.) + + </para> + + <para> + + The following code sets the &cv-link-CCFLAGS; construction + variable in response to the <varname>debug</varname> + flag being set in the &ARGUMENTS; dictionary: + + </para> + + <scons_example name="ARGUMENTS"> + <file name="SConstruct" printme="1"> + env = Environment() + debug = ARGUMENTS.get('debug', 0) + if int(debug): + env.Append(CCFLAGS = '-g') + env.Program('prog.c') + </file> + <file name="prog.c"> + prog.c + </file> + </scons_example> + + <para> + + This results in the <varname>-g</varname> + compiler option being used when + <literal>debug=1</literal> + is used on the command line: + + </para> + + <scons_output example="ARGUMENTS"> + <scons_output_command>scons -Q debug=0</scons_output_command> + <scons_output_command>scons -Q debug=0</scons_output_command> + <scons_output_command>scons -Q debug=1</scons_output_command> + <scons_output_command>scons -Q debug=1</scons_output_command> + </scons_output> + + <para> + + Notice that &SCons; keeps track of + the last values used to build the object files, + and as a result correctly rebuilds + the object and executable files + only when the value of the <literal>debug</literal> + argument has changed. + + </para> + + <para> + + The &ARGUMENTS; dictionary has two minor drawbacks. + First, because it is a dictionary, + it can only store one value for each specified keyword, + and thus only "remembers" the last setting + for each keyword on the command line. + This makes the &ARGUMENTS; dictionary + inappropriate if users should be able to + specify multiple values + on the command line for a given keyword. + Second, it does not preserve + the order in which the variable settings + were specified, + which is a problem if + you want the configuration to + behave differently in response + to the order in which the build + variable settings were specified on the command line. + + </para> + + <para> + + To accomodate these requirements, + &SCons; provides an &ARGLIST; variable + that gives you direct access to + <varname>variable</varname>=<varname>value</varname> + settings on the command line, + in the exact order they were specified, + and without removing any duplicate settings. + Each element in the &ARGLIST; variable + is itself a two-element list + containing the keyword and the value + of the setting, + and you must loop through, + or otherwise select from, + the elements of &ARGLIST; to + process the specific settings you want + in whatever way is appropriate for your configuration. + For example, + the following code to let the user + add to the &CPPDEFINES; construction variable + by specifying multiple + <varname>define=</varname> + settings on the command line: + + </para> + + <scons_example name="ARGLIST"> + <file name="SConstruct" printme="1"> + cppdefines = [] + for key, value in ARGLIST: + if key == 'define': + cppdefines.append(value) + env = Environment(CPPDEFINES = cppdefines) + env.Object('prog.c') + </file> + <file name="prog.c"> + prog.c + </file> + </scons_example> + + <para> + + Yields the following output: + + </para> + + <scons_output example="ARGLIST"> + <scons_output_command>scons -Q define=FOO</scons_output_command> + <scons_output_command>scons -Q define=FOO define=BAR</scons_output_command> + </scons_output> + + <para> + + Note that the &ARGLIST; and &ARGUMENTS; + variables do not interfere with each other, + but merely provide slightly different views + into how the user specified + <varname>variable</varname>=<varname>value</varname> + settings on the command line. + You can use both variables in the same + &SCons; configuration. + In general, the &ARGUMENTS; dictionary + is more convenient to use, + (since you can just fetch variable + settings through a dictionary access), + and the &ARGLIST; list + is more flexible + (since you can examine the + specific order in which + the user's command-line variabe settings). + + </para> + + <section> + <title>Controlling Command-Line Build Variables</title> + + <para> + + Being able to use a command-line build variable like + <literal>debug=1</literal> is handy, + but it can be a chore to write specific Python code + to recognize each such variable, + check for errors and provide appropriate messages, + and apply the values to a construction variable. + To help with this, + &SCons; supports a class to + define such build variables easily, + and a mechanism to apply the + build variables to a construction environment. + This allows you to control how the build variables affect + construction environments. + + </para> + + <para> + + For example, suppose that you want users to set + a &RELEASE; construction variable on the + command line whenever the time comes to build + a program for release, + and that the value of this variable + should be added to the command line + with the appropriate <literal>-D</literal> option + (or other command line option) + to pass the value to the C compiler. + Here's how you might do that by setting + the appropriate value in a dictionary for the + &cv-link-CPPDEFINES; construction variable: + + </para> + + <scons_example name="Variables1"> + <file name="SConstruct" printme="1"> + vars = Variables() + vars.Add('RELEASE', 'Set to 1 to build for release', 0) + env = Environment(variables = vars, + CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) + env.Program(['foo.c', 'bar.c']) + </file> + <file name="foo.c"> + foo.c + </file> + <file name="bar.c"> + bar.c + </file> + </scons_example> + + <para> + + This &SConstruct; file first creates a &Variables; object + (the <literal>vars = Variables()</literal> call), + and then uses the object's &Add; + method to indicate that the &RELEASE; + variable can be set on the command line, + and that its default value will be <literal>0</literal> + (the third argument to the &Add; method). + The second argument is a line of help text; + we'll learn how to use it in the next section. + + </para> + + <para> + + We then pass the created &Variables; + object as a &variables; keyword argument + to the &Environment; call + used to create the construction environment. + This then allows a user to set the + &RELEASE; build variable on the command line + and have the variable show up in + the command line used to build each object from + a C source file: + + </para> + + <scons_output example="Variables1"> + <scons_output_command>scons -Q RELEASE=1</scons_output_command> + </scons_output> + + <para> + + NOTE: Before &SCons; release 0.98.1, these build variables + were known as "command-line build options." + The class was actually named the &Options; class, + and in the sections below, + the various functions were named + &BoolOption;, &EnumOption;, &ListOption;, + &PathOption;, &PackageOption; and &AddOptions;. + These older names still work, + and you may encounter them in older + &SConscript; fles, + but their use is discouraged + and will be officially deprecated some day. + + </para> + + </section> + + <section> + <title>Providing Help for Command-Line Build Variables</title> + + <para> + + To make command-line build variables most useful, + you ideally want to provide + some help text that will describe + the available variables + when the user runs <literal>scons -h</literal>. + You could write this text by hand, + but &SCons; provides an easier way. + &Variables; objects support a + &GenerateHelpText; method + that will, as its name suggests, + generate text that describes + the various variables that + have been added to it. + You then pass the output from this method to + the &Help; function: + + </para> + + <scons_example name="Variables_Help"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add('RELEASE', 'Set to 1 to build for release', 0) + env = Environment(variables = vars) + Help(vars.GenerateHelpText(env)) + </file> + </scons_example> + + <para> + + &SCons; will now display some useful text + when the <literal>-h</literal> option is used: + + </para> + + <scons_output example="Variables_Help"> + <scons_output_command>scons -Q -h</scons_output_command> + </scons_output> + + <para> + + Notice that the help output shows the default value, + and the current actual value of the build variable. + + </para> + + </section> + + <section> + <title>Reading Build Variables From a File</title> + + <para> + + Giving the user a way to specify the + value of a build variable on the command line + is useful, + but can still be tedious + if users must specify the variable + every time they run &SCons;. + We can let users provide customized build variable settings + in a local file by providing a + file name when we create the + &Variables; object: + + </para> + + <scons_example name="Variables_custom_py_1"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add('RELEASE', 'Set to 1 to build for release', 0) + env = Environment(variables = vars, + CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) + env.Program(['foo.c', 'bar.c']) + Help(vars.GenerateHelpText(env)) + </file> + <file name="foo.c"> + foo.c + </file> + <file name="bar.c"> + bar.c + </file> + <file name="custom.py"> + RELEASE = 1 + </file> + </scons_example> + + <para> + + This then allows the user to control the &RELEASE; + variable by setting it in the &custom_py; file: + + </para> + + <scons_example_file example="Variables_custom_py_1" name="custom.py"></scons_example_file> + + <para> + + Note that this file is actually executed + like a Python script. + Now when we run &SCons;: + + </para> + + <scons_output example="Variables_custom_py_1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + And if we change the contents of &custom_py; to: + + </para> + + <scons_example name="Variables_custom_py_2"> + <file name="SConstruct"> + vars = Variables('custom.py') + vars.Add('RELEASE', 'Set to 1 to build for release', 0) + env = Environment(variables = vars, + CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) + env.Program(['foo.c', 'bar.c']) + Help(vars.GenerateHelpText(env)) + </file> + <file name="foo.c"> + foo.c + </file> + <file name="bar.c"> + bar.c + </file> + <file name="custom.py" printme="1"> + RELEASE = 0 + </file> + </scons_example> + + <para> + + The object files are rebuilt appropriately + with the new variable: + + </para> + + <scons_output example="Variables_custom_py_2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Pre-Defined Build Variable Functions</title> + + <para> + + &SCons; provides a number of functions + that provide ready-made behaviors + for various types of command-line build variables. + + </para> + + <section> + <title>True/False Values: the &BoolVariable; Build Variable Function</title> + + <para> + + It's often handy to be able to specify a + variable that controls a simple Boolean variable + with a &true; or &false; value. + It would be even more handy to accomodate + users who have different preferences for how to represent + &true; or &false; values. + The &BoolVariable; function + makes it easy to accomodate these + common representations of + &true; or &false;. + + </para> + + <para> + + The &BoolVariable; function takes three arguments: + the name of the build variable, + the default value of the build variable, + and the help string for the variable. + It then returns appropriate information for + passing to the &Add; method of a &Variables; object, like so: + + </para> + + <scons_example name="BoolVariable"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add(BoolVariable('RELEASE', 'Set to build for release', 0)) + env = Environment(variables = vars, + CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + </scons_example> + + <para> + + With this build variable, + the &RELEASE; variable can now be enabled by + setting it to the value <literal>yes</literal> + or <literal>t</literal>: + + </para> + + <scons_output example="BoolVariable"> + <scons_output_command>scons -Q RELEASE=yes foo.o</scons_output_command> + </scons_output> + + <scons_output example="BoolVariable"> + <scons_output_command>scons -Q RELEASE=t foo.o</scons_output_command> + </scons_output> + + <para> + + Other values that equate to &true; include + <literal>y</literal>, + <literal>1</literal>, + <literal>on</literal> + and + <literal>all</literal>. + + </para> + + <para> + + Conversely, &RELEASE; may now be given a &false; + value by setting it to + <literal>no</literal> + or + <literal>f</literal>: + + </para> + + <scons_output example="BoolVariable"> + <scons_output_command>scons -Q RELEASE=no foo.o</scons_output_command> + </scons_output> + + <scons_output example="BoolVariable"> + <scons_output_command>scons -Q RELEASE=f foo.o</scons_output_command> + </scons_output> + + <para> + + Other values that equate to &false; include + <literal>n</literal>, + <literal>0</literal>, + <literal>off</literal> + and + <literal>none</literal>. + + </para> + + <para> + + Lastly, if a user tries to specify + any other value, + &SCons; supplies an appropriate error message: + + </para> + + <scons_output example="BoolVariable"> + <scons_output_command>scons -Q RELEASE=bad_value foo.o</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Single Value From a List: the &EnumVariable; Build Variable Function</title> + + <para> + + Suppose that we want a user to be able to + set a &COLOR; variable + that selects a background color to be + displayed by an application, + but that we want to restrict the + choices to a specific set of allowed colors. + This can be set up quite easily + using the &EnumVariable;, + which takes a list of &allowed_values + in addition to the variable name, + default value, + and help text arguments: + + </para> + + <scons_example name="EnumVariable"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add(EnumVariable('COLOR', 'Set background color', 'red', + allowed_values=('red', 'green', 'blue'))) + env = Environment(variables = vars, + CPPDEFINES={'COLOR' : '"${COLOR}"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + </scons_example> + + <para> + + The user can now explicity set the &COLOR; build variable + to any of the specified allowed values: + + </para> + + <scons_output example="EnumVariable"> + <scons_output_command>scons -Q COLOR=red foo.o</scons_output_command> + <scons_output_command>scons -Q COLOR=blue foo.o</scons_output_command> + <scons_output_command>scons -Q COLOR=green foo.o</scons_output_command> + </scons_output> + + <para> + + But, almost more importantly, + an attempt to set &COLOR; + to a value that's not in the list + generates an error message: + + </para> + + <scons_output example="EnumVariable"> + <scons_output_command>scons -Q COLOR=magenta foo.o</scons_output_command> + </scons_output> + + <para> + + The &EnumVariable; function also supports a way + to map alternate names to allowed values. + Suppose, for example, + that we want to allow the user + to use the word <literal>navy</literal> as a synonym for + <literal>blue</literal>. + We do this by adding a ↦ dictionary + that will map its key values + to the desired legal value: + + </para> + + <scons_example name="EnumVariable_map"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add(EnumVariable('COLOR', 'Set background color', 'red', + allowed_values=('red', 'green', 'blue'), + map={'navy':'blue'})) + env = Environment(variables = vars, + CPPDEFINES={'COLOR' : '"${COLOR}"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + </scons_example> + + <para> + + As desired, the user can then use + <literal>navy</literal> on the command line, + and &SCons; will translate it into <literal>blue</literal> + when it comes time to use the &COLOR; + variable to build a target: + + </para> + + <scons_output example="EnumVariable_map"> + <scons_output_command>scons -Q COLOR=navy foo.o</scons_output_command> + </scons_output> + + <para> + + By default, when using the &EnumVariable; function, + arguments that differ + from the legal values + only in case + are treated as illegal values: + + </para> + + <scons_output example="EnumVariable"> + <scons_output_command>scons -Q COLOR=Red foo.o</scons_output_command> + <scons_output_command>scons -Q COLOR=BLUE foo.o</scons_output_command> + <scons_output_command>scons -Q COLOR=nAvY foo.o</scons_output_command> + </scons_output> + + <para> + + The &EnumVariable; function can take an additional + &ignorecase; keyword argument that, + when set to <literal>1</literal>, + tells &SCons; to allow case differences + when the values are specified: + + </para> + + <scons_example name="EnumVariable_ic1"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add(EnumVariable('COLOR', 'Set background color', 'red', + allowed_values=('red', 'green', 'blue'), + map={'navy':'blue'}, + ignorecase=1)) + env = Environment(variables = vars, + CPPDEFINES={'COLOR' : '"${COLOR}"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + </scons_example> + + <para> + + Which yields the output: + + </para> + + <scons_output example="EnumVariable_ic1"> + <scons_output_command>scons -Q COLOR=Red foo.o</scons_output_command> + <scons_output_command>scons -Q COLOR=BLUE foo.o</scons_output_command> + <scons_output_command>scons -Q COLOR=nAvY foo.o</scons_output_command> + <scons_output_command>scons -Q COLOR=green foo.o</scons_output_command> + </scons_output> + + <para> + + Notice that an &ignorecase; value of <literal>1</literal> + preserves the case-spelling that the user supplied. + If you want &SCons; to translate the names + into lower-case, + regardless of the case used by the user, + specify an &ignorecase; value of <literal>2</literal>: + + </para> + + <scons_example name="EnumVariable_ic2"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add(EnumVariable('COLOR', 'Set background color', 'red', + allowed_values=('red', 'green', 'blue'), + map={'navy':'blue'}, + ignorecase=2)) + env = Environment(variables = vars, + CPPDEFINES={'COLOR' : '"${COLOR}"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + </scons_example> + + <para> + + Now &SCons; will use values of + <literal>red</literal>, + <literal>green</literal> or + <literal>blue</literal> + regardless of how the user spells + those values on the command line: + + </para> + + <scons_output example="EnumVariable_ic2"> + <scons_output_command>scons -Q COLOR=Red foo.o</scons_output_command> + <scons_output_command>scons -Q COLOR=nAvY foo.o</scons_output_command> + <scons_output_command>scons -Q COLOR=GREEN foo.o</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Multiple Values From a List: the &ListVariable; Build Variable Function</title> + + <para> + + Another way in which you might want to allow users + to control a build variable is to + specify a list of one or more legal values. + &SCons; supports this through the &ListVariable; function. + If, for example, we want a user to be able to set a + &COLORS; variable to one or more of the legal list of values: + + </para> + + <scons_example name="ListVariable"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add(ListVariable('COLORS', 'List of colors', 0, + ['red', 'green', 'blue'])) + env = Environment(variables = vars, + CPPDEFINES={'COLORS' : '"${COLORS}"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + </scons_example> + + <para> + + A user can now specify a comma-separated list + of legal values, + which will get translated into a space-separated + list for passing to the any build commands: + + </para> + + <scons_output example="ListVariable"> + <scons_output_command>scons -Q COLORS=red,blue foo.o</scons_output_command> + <scons_output_command>scons -Q COLORS=blue,green,red foo.o</scons_output_command> + </scons_output> + + <para> + + In addition, the &ListVariable; function + allows the user to specify explicit keywords of + &all; or &none; + to select all of the legal values, + or none of them, respectively: + + </para> + + <scons_output example="ListVariable"> + <scons_output_command>scons -Q COLORS=all foo.o</scons_output_command> + <scons_output_command>scons -Q COLORS=none foo.o</scons_output_command> + </scons_output> + + <para> + + And, of course, an illegal value + still generates an error message: + + </para> + + <scons_output example="ListVariable"> + <scons_output_command>scons -Q COLORS=magenta foo.o</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Path Names: the &PathVariable; Build Variable Function</title> + + <para> + + &SCons; supports a &PathVariable; function + to make it easy to create a build variable + to control an expected path name. + If, for example, you need to + define a variable in the preprocessor + that controls the location of a + configuration file: + + </para> + + <scons_example name="PathVariable"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add(PathVariable('CONFIG', + 'Path to configuration file', + '__ROOT__/etc/my_config')) + env = Environment(variables = vars, + CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + <file name="__ROOT__/etc/my_config"> + /opt/location + </file> + <file name="__ROOT__/usr/local/etc/other_config"> + /opt/location + </file> + </scons_example> + + <para> + + This then allows the user to + override the &CONFIG; build variable + on the command line as necessary: + + </para> + + <scons_output example="PathVariable"> + <scons_output_command>scons -Q foo.o</scons_output_command> + <scons_output_command>scons -Q CONFIG=__ROOT__/usr/local/etc/other_config foo.o</scons_output_command> + </scons_output> + + <para> + + By default, &PathVariable; checks to make sure + that the specified path exists and generates an error if it + doesn't: + + </para> + + <scons_output example="PathVariable"> + <scons_output_command>scons -Q CONFIG=__ROOT__/does/not/exist foo.o</scons_output_command> + </scons_output> + + <para> + + &PathVariable; provides a number of methods + that you can use to change this behavior. + If you want to ensure that any specified paths are, + in fact, files and not directories, + use the &PathVariable_PathIsFile; method: + + </para> + + <scons_example name="PathIsFile"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add(PathVariable('CONFIG', + 'Path to configuration file', + '__ROOT__/etc/my_config', + PathVariable.PathIsFile)) + env = Environment(variables = vars, + CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + <file name="__ROOT__/etc/my_config"> + /opt/location + </file> + </scons_example> + + <para> + + Conversely, to ensure that any specified paths are + directories and not files, + use the &PathVariable_PathIsDir; method: + + </para> + + <scons_example name="PathIsDir"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add(PathVariable('DBDIR', + 'Path to database directory', + '__ROOT__/var/my_dbdir', + PathVariable.PathIsDir)) + env = Environment(variables = vars, + CPPDEFINES={'DBDIR' : '"$DBDIR"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + <file name="__ROOT__/var/my_dbdir"> + /opt/location + </file> + </scons_example> + + <para> + + If you want to make sure that any specified paths + are directories, + and you would like the directory created + if it doesn't already exist, + use the &PathVariable_PathIsDirCreate; method: + + </para> + + <scons_example name="PathIsDirCreate"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add(PathVariable('DBDIR', + 'Path to database directory', + '__ROOT__/var/my_dbdir', + PathVariable.PathIsDirCreate)) + env = Environment(variables = vars, + CPPDEFINES={'DBDIR' : '"$DBDIR"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + <file name="__ROOT__/var/my_dbdir"> + /opt/location + </file> + </scons_example> + + <para> + + Lastly, if you don't care whether the path exists, + is a file, or a directory, + use the &PathVariable_PathAccept; method + to accept any path that the user supplies: + + </para> + + <scons_example name="PathAccept"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add(PathVariable('OUTPUT', + 'Path to output file or directory', + None, + PathVariable.PathAccept)) + env = Environment(variables = vars, + CPPDEFINES={'OUTPUT' : '"$OUTPUT"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + </scons_example> + + </section> + + <section> + <title>Enabled/Disabled Path Names: the &PackageVariable; Build Variable Function</title> + + <para> + + Sometimes you want to give users + even more control over a path name variable, + allowing them to explicitly enable or + disable the path name + by using <literal>yes</literal> or <literal>no</literal> keywords, + in addition to allow them + to supply an explicit path name. + &SCons; supports the &PackageVariable; + function to support this: + + </para> + + <scons_example name="PackageVariable"> + <file name="SConstruct" printme="1"> + vars = Variables('custom.py') + vars.Add(PackageVariable('PACKAGE', + 'Location package', + '__ROOT__/opt/location')) + env = Environment(variables = vars, + CPPDEFINES={'PACKAGE' : '"$PACKAGE"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + <file name="__ROOT__/opt/location"> + /opt/location + </file> + <file name="__ROOT__/usr/local/location"> + /opt/location + </file> + </scons_example> + + <para> + + When the &SConscript; file uses the &PackageVariable; funciton, + user can now still use the default + or supply an overriding path name, + but can now explicitly set the + specified variable to a value + that indicates the package should be enabled + (in which case the default should be used) + or disabled: + + </para> + + <scons_output example="PackageVariable"> + <scons_output_command>scons -Q foo.o</scons_output_command> + <scons_output_command>scons -Q PACKAGE=__ROOT__/usr/local/location foo.o</scons_output_command> + <scons_output_command>scons -Q PACKAGE=yes foo.o</scons_output_command> + <scons_output_command>scons -Q PACKAGE=no foo.o</scons_output_command> + </scons_output> + + </section> + + </section> + + <section> + <title>Adding Multiple Command-Line Build Variables at Once</title> + + <para> + + Lastly, &SCons; provides a way to add + multiple build variables to a &Variables; object at once. + Instead of having to call the &Add; method + multiple times, + you can call the &AddVariables; + method with a list of build variables + to be added to the object. + Each build variable is specified + as either a tuple of arguments, + just like you'd pass to the &Add; method itself, + or as a call to one of the pre-defined + functions for pre-packaged command-line build variables. + in any order: + + </para> + + <scons_example name="AddVariables_1"> + <file name="SConstruct" printme="1"> + vars = Variables() + vars.AddVariables( + ('RELEASE', 'Set to 1 to build for release', 0), + ('CONFIG', 'Configuration file', '/etc/my_config'), + BoolVariable('warnings', 'compilation with -Wall and similiar', 1), + EnumVariable('debug', 'debug output and symbols', 'no', + allowed_values=('yes', 'no', 'full'), + map={}, ignorecase=0), # case sensitive + ListVariable('shared', + 'libraries to build as shared libraries', + 'all', + names = list_of_libs), + PackageVariable('x11', + 'use X11 installed here (yes = search some places)', + 'yes'), + PathVariable('qtdir', 'where the root of Qt is installed', qtdir), + ) + </file> + </scons_example> + + <para> + </para> + + </section> + + <section> + <title>Handling Unknown Command-Line Build Variables: the &UnknownVariables; Function</title> + + <para> + + Users may, of course, + occasionally misspell variable names in their command-line settings. + &SCons; does not generate an error or warning + for any unknown variables the users specifies on the command line. + (This is in no small part because you may be + processing the arguments directly using the &ARGUMENTS; dictionary, + and therefore &SCons; can't know in the general case + whether a given "misspelled" variable is + really unknown and a potential problem, + or something that your &SConscript; file + will handle directly with some Python code.) + + </para> + + <para> + + If, however, you're using a &Variables; object to + define a specific set of command-line build variables + that you expect users to be able to set, + you may want to provide an error + message or warning of your own + if the user supplies a variable setting + that is <emphasis>not</emphasis> among + the defined list of variable names known to the &Variables; object. + You can do this by calling the &UnknownVariables; + method of the &Variables; object: + + </para> + + <scons_example name="UnknownVariables"> + <file name="SConstruct" printme="1"> + vars = Variables(None) + vars.Add('RELEASE', 'Set to 1 to build for release', 0) + env = Environment(variables = vars, + CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) + unknown = vars.UnknownVariables() + if unknown: + print "Unknown variables:", unknown.keys() + Exit(1) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + </scons_example> + + <para> + + The &UnknownVariables; method returns a dictionary + containing the keywords and values + of any variables the user specified on the command line + that are <emphasis>not</emphasis> + among the variables known to the &Variables; object + (from having been specified using + the &Variables; object's&Add; method). + In the examble above, + we check for whether the dictionary + returned by the &UnknownVariables; is non-empty, + and if so print the Python list + containing the names of the unknwown variables + and then call the &Exit; function + to terminate &SCons;: + + </para> + + <scons_output example="UnknownVariables"> + <scons_output_command>scons -Q NOT_KNOWN=foo</scons_output_command> + </scons_output> + + <para> + + Of course, you can process the items in the + dictionary returned by the &UnknownVariables; function + in any way appropriate to your build configuration, + including just printing a warning message + but not exiting, + logging an error somewhere, + etc. + + </para> + + <para> + + Note that you must delay the call of &UnknownVariables; + until after you have applied the &Variables; object + to a construction environment + with the <literal>variables=</literal> + keyword argument of an &Environment; call. + + </para> + + </section> + + </section> + + <section id="sect-command-line-targets"> + <title>Command-Line Targets</title> + + <section> + <title>Fetching Command-Line Targets: the &COMMAND_LINE_TARGETS; Variable</title> + + <para> + + &SCons; supports a &COMMAND_LINE_TARGETS; variable + that lets you fetch the list of targets that the + user specified on the command line. + You can use the targets to manipulate the + build in any way you wish. + As a simple example, + suppose that you want to print a reminder + to the user whenever a specific program is built. + You can do this by checking for the + target in the &COMMAND_LINE_TARGETS; list: + + </para> + + <scons_example name="COMMAND_LINE_TARGETS"> + <file name="SConstruct" printme="1"> + if 'bar' in COMMAND_LINE_TARGETS: + print "Don't forget to copy `bar' to the archive!" + Default(Program('foo.c')) + Program('bar.c') + </file> + <file name="foo.c"> + foo.c + </file> + <file name="bar.c"> + foo.c + </file> + </scons_example> + + <para> + + Then, running &SCons; with the default target + works as it always does, + but explicity specifying the &bar; target + on the command line generates the warning message: + + </para> + + <scons_output example="COMMAND_LINE_TARGETS"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q bar</scons_output_command> + </scons_output> + + <para> + + Another practical use for the &COMMAND_LINE_TARGETS; variable + might be to speed up a build + by only reading certain subsidiary &SConscript; + files if a specific target is requested. + + </para> + + </section> + + <section> + <title>Controlling the Default Targets: the &Default; Function</title> + + <para> + + One of the most basic things you can control + is which targets &SCons; will build by default--that is, + when there are no targets specified on the command line. + As mentioned previously, + &SCons; will normally build every target + in or below the current directory + by default--that is, when you don't + explicitly specify one or more targets + on the command line. + Sometimes, however, you may want + to specify explicitly that only + certain programs, or programs in certain directories, + should be built by default. + You do this with the &Default; function: + + </para> + + <scons_example name="Default1"> + <file name="SConstruct" printme="1"> + env = Environment() + hello = env.Program('hello.c') + env.Program('goodbye.c') + Default(hello) + </file> + <file name="hello.c"> + hello.c + </file> + <file name="goodbye.c"> + goodbye.c + </file> + </scons_example> + + <para> + + This &SConstruct; file knows how to build two programs, + &hello; and &goodbye;, + but only builds the + &hello; program by default: + + </para> + + <scons_output example="Default1"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q goodbye</scons_output_command> + </scons_output> + + <para> + + Note that, even when you use the &Default; + function in your &SConstruct; file, + you can still explicitly specify the current directory + (<literal>.</literal>) on the command line + to tell &SCons; to build + everything in (or below) the current directory: + + </para> + + <scons_output example="Default1"> + <scons_output_command>scons -Q .</scons_output_command> + </scons_output> + + <para> + + You can also call the &Default; + function more than once, + in which case each call + adds to the list of targets to be built by default: + + </para> + + <scons_example name="Default2"> + <file name="SConstruct" printme="1"> + env = Environment() + prog1 = env.Program('prog1.c') + Default(prog1) + prog2 = env.Program('prog2.c') + prog3 = env.Program('prog3.c') + Default(prog3) + </file> + <file name="prog1.c"> + prog1.c + </file> + <file name="prog2.c"> + prog2.c + </file> + <file name="prog3.c"> + prog3.c + </file> + </scons_example> + + <para> + + Or you can specify more than one target + in a single call to the &Default; function: + + </para> + + <programlisting> + env = Environment() + prog1 = env.Program('prog1.c') + prog2 = env.Program('prog2.c') + prog3 = env.Program('prog3.c') + Default(prog1, prog3) + </programlisting> + + <para> + + Either of these last two examples + will build only the + <application>prog1</application> + and + <application>prog3</application> + programs by default: + + </para> + + <scons_output example="Default2"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q .</scons_output_command> + </scons_output> + + <para> + + You can list a directory as + an argument to &Default;: + + </para> + + <scons_example name="Default3"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Program(['prog1/main.c', 'prog1/foo.c']) + env.Program(['prog2/main.c', 'prog2/bar.c']) + Default('prog1') + </file> + <directory name="prog1"></directory> + <directory name="prog2"></directory> + <file name="prog1/main.c"> + int main() { printf("prog1/main.c\n"); } + </file> + <file name="prog1/foo.c"> + int foo() { printf("prog1/foo.c\n"); } + </file> + <file name="prog2/main.c"> + int main() { printf("prog2/main.c\n"); } + </file> + <file name="prog2/bar.c"> + int bar() { printf("prog2/bar.c\n"); } + </file> + </scons_example> + + <para> + + In which case only the target(s) in that + directory will be built by default: + + </para> + + <scons_output example="Default3"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q .</scons_output_command> + </scons_output> + + <para> + + Lastly, if for some reason you don't want + any targets built by default, + you can use the Python <literal>None</literal> + variable: + + </para> + + <scons_example name="Default4"> + <file name="SConstruct" printme="1"> + env = Environment() + prog1 = env.Program('prog1.c') + prog2 = env.Program('prog2.c') + Default(None) + </file> + <file name="prog1.c"> + prog1.c + </file> + <file name="prog2.c"> + prog2.c + </file> + </scons_example> + + <para> + + Which would produce build output like: + + </para> + + <scons_output example="Default4"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q .</scons_output_command> + </scons_output> + + <section> + <title>Fetching the List of Default Targets: the &DEFAULT_TARGETS; Variable</title> + + <para> + + &SCons; supports a &DEFAULT_TARGETS; variable + that lets you get at the current list of default targets. + The &DEFAULT_TARGETS variable has + two important differences from the &COMMAND_LINE_TARGETS; variable. + First, the &DEFAULT_TARGETS; variable is a list of + internal &SCons; nodes, + so you need to convert the list elements to strings + if you want to print them or look for a specific target name. + Fortunately, you can do this easily + by using the Python <function>map</function> function + to run the list through <function>str</function>: + + </para> + + <scons_example name="DEFAULT_TARGETS_1"> + <file name="SConstruct" printme="1"> + prog1 = Program('prog1.c') + Default(prog1) + print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS) + </file> + <file name="prog1.c"> + prog1.c + </file> + </scons_example> + + <para> + + (Keep in mind that all of the manipulation of the + &DEFAULT_TARGETS; list takes place during the + first phase when &SCons; is reading up the &SConscript; files, + which is obvious if + we leave off the <literal>-Q</literal> flag when we run &SCons;:) + + </para> + + <scons_output example="DEFAULT_TARGETS_1"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + Second, + the contents of the &DEFAULT_TARGETS; list change + in response to calls to the &Default: function, + as you can see from the following &SConstruct; file: + + </para> + + <scons_example name="DEFAULT_TARGETS_2"> + <file name="SConstruct" printme="1"> + prog1 = Program('prog1.c') + Default(prog1) + print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS) + prog2 = Program('prog2.c') + Default(prog2) + print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS) + </file> + <file name="prog1.c"> + prog1.c + </file> + <file name="prog2.c"> + prog2.c + </file> + </scons_example> + + <para> + + Which yields the output: + + </para> + + <scons_output example="DEFAULT_TARGETS_2"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + In practice, this simply means that you + need to pay attention to the order in + which you call the &Default; function + and refer to the &DEFAULT_TARGETS; list, + to make sure that you don't examine the + list before you've added the default targets + you expect to find in it. + + </para> + + </section> + + </section> + + <section> + <title>Fetching the List of Build Targets, Regardless of Origin: the &BUILD_TARGETS; Variable</title> + + <para> + + We've already been introduced to the + &COMMAND_LINE_TARGETS; variable, + which contains a list of targets specified on the command line, + and the &DEFAULT_TARGETS; variable, + which contains a list of targets specified + via calls to the &Default; method or function. + Sometimes, however, + you want a list of whatever targets + &SCons; will try to build, + regardless of whether the targets came from the + command line or a &Default; call. + You could code this up by hand, as follows: + + </para> + + <sconstruct> + if COMMAND_LINE_TARGETS: + targets = COMMAND_LINE_TARGETS + else: + targets = DEFAULT_TARGETS + </sconstruct> + + <para> + + &SCons;, however, provides a convenient + &BUILD_TARGETS; variable + that eliminates the need for this by-hand manipulation. + Essentially, the &BUILD_TARGETS; variable + contains a list of the command-line targets, + if any were specified, + and if no command-line targets were specified, + it contains a list of the targets specified + via the &Default; method or function. + + </para> + + <para> + + Because &BUILD_TARGETS; may contain a list of &SCons; nodes, + you must convert the list elements to strings + if you want to print them or look for a specific target name, + just like the &DEFAULT_TARGETS; list: + + </para> + + <scons_example name="BUILD_TARGETS_1"> + <file name="SConstruct" printme="1"> + prog1 = Program('prog1.c') + Program('prog2.c') + Default(prog1) + print "BUILD_TARGETS is", map(str, BUILD_TARGETS) + </file> + <file name="prog1.c"> + prog1.c + </file> + <file name="prog2.c"> + prog2.c + </file> + </scons_example> + + <para> + + Notice how the value of &BUILD_TARGETS; + changes depending on whether a target is + specified on the command line: + + </para> + + <scons_output example="BUILD_TARGETS_1"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q prog2</scons_output_command> + <scons_output_command>scons -Q -c .</scons_output_command> + </scons_output> + + </section> + + </section> diff --git a/doc/user/command-line.xml b/doc/user/command-line.xml new file mode 100644 index 0000000..630a9b2 --- /dev/null +++ b/doc/user/command-line.xml @@ -0,0 +1,2243 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; provides a number of ways + for the writer of the &SConscript; files + to give the users who will run &SCons; + a great deal of control over the build execution. + The arguments that the user can specify on + the command line are broken down into three types: + + </para> + + <variablelist> + + <varlistentry> + <term>Options</term> + + <listitem> + <para> + + Command-line options always begin with + one or two <literal>-</literal> (hyphen) characters. + &SCons; provides ways for you to examine + and set options values from within your &SConscript; files, + as well as the ability to define your own + custom options. + See <xref linkend="sect-command-line-options"></xref>, below. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Variables</term> + + <listitem> + <para> + + Any command-line argument containing an <literal>=</literal> + (equal sign) is considered a variable setting with the form + <varname>variable</varname>=<varname>value</varname> + &SCons; provides direct access to + all of the command-line variable settings, + the ability to apply command-line variable settings + to construction environments, + and functions for configuring + specific types of variables + (Boolean values, path names, etc.) + with automatic validation of the user's specified values. + See <xref linkend="sect-command-line-variables"></xref>, below. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Targets</term> + + <listitem> + <para> + + Any command-line argument that is not an option + or a variable setting + (does not begin with a hyphen + and does not contain an equal sign) + is considered a target that the user + (presumably) wants &SCons; to build. + A list of Node objects representing + the target or targets to build. + &SCons; provides access to the list of specified targets, + as well as ways to set the default list of targets + from within the &SConscript; files. + See <xref linkend="sect-command-line-targets"></xref>, below. + + </para> + </listitem> + </varlistentry> + + </variablelist> + + <section id="sect-command-line-options"> + <title>Command-Line Options</title> + + <para> + + &SCons; has many <emphasis>command-line options</emphasis> + that control its behavior. + A &SCons; <emphasis>command-line option</emphasis> + always begins with one or two <literal>-</literal> (hyphen) + characters. + + </para> + + <section> + <title>Not Having to Specify Command-Line Options Each Time: the &SCONSFLAGS; Environment Variable</title> + + <para> + + Users may find themselves supplying + the same command-line options every time + they run &SCons;. + For example, you might find it saves time + to specify a value of <literal>-j 2</literal> + to have &SCons; run up to two build commands in parallel. + To avoid having to type <literal>-j 2</literal> by hand + every time, + you can set the external environment variable + &SCONSFLAGS; to a string containing + command-line options that you want &SCons; to use. + + </para> + + <para> + + If, for example, + you're using a POSIX shell that's + compatible with the Bourne shell, + and you always want &SCons; to use the + <literal>-Q</literal> option, + you can set the &SCONSFLAGS; + environment as follows: + + </para> + + + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + scons: done reading SConscript files. + scons: Building targets ... + ... [build output] ... + scons: done building targets. + % <userinput>export SCONSFLAGS="-Q"</userinput> + % <userinput>scons</userinput> + ... [build output] ... + </screen> + + <para> + + Users of &csh;-style shells on POSIX systems + can set the &SCONSFLAGS; environment as follows: + + </para> + + <screen> + $ <userinput>setenv SCONSFLAGS "-Q"</userinput> + </screen> + + <para> + + Windows users may typically want to set the + &SCONSFLAGS; in the appropriate tab of the + <literal>System Properties</literal> window. + + </para> + + </section> + + <section> + <title>Getting Values Set by Command-Line Options: the &GetOption; Function</title> + + <para> + + &SCons; provides the &GetOption; function + to get the values set by the various command-line options. + One common use of this is to check whether or not + the <literal>-h</literal> or <literal>--help</literal> option + has been specified. + Normally, &SCons; does not print its help text + until after it has read all of the &SConscript; files, + because it's possible that help text has been added + by some subsidiary &SConscript; file deep in the + source tree hierarchy. + Of course, reading all of the &SConscript; files + takes extra time. + + </para> + + <para> + + If you know that your configuration does not define + any additional help text in subsidiary &SConscript; files, + you can speed up the command-line help available to users + by using the &GetOption; function to load the + subsidiary &SConscript; files only if the + the user has <emphasis>not</emphasis> specified + the <literal>-h</literal> or <literal>--help</literal> option, + like so: + + </para> + + <programlisting></programlisting> + + <para> + + In general, the string that you pass to the + &GetOption; function to fetch the value of a command-line + option setting is the same as the "most common" long option name + (beginning with two hyphen characters), + although there are some exceptions. + The list of &SCons; command-line options + and the &GetOption; strings for fetching them, + are available in the + <xref linkend="sect-command-line-option-strings"></xref> section, + below. + + </para> + + </section> + + <section> + <title>Setting Values of Command-Line Options: the &SetOption; Function</title> + + <para> + + You can also set the values of &SCons; + command-line options from within the &SConscript; files + by using the &SetOption; function. + The strings that you use to set the values of &SCons; + command-line options are available in the + <xref linkend="sect-command-line-option-strings"></xref> section, + below. + + </para> + + <para> + + One use of the &SetOption; function is to + specify a value for the <literal>-j</literal> + or <literal>--jobs</literal> option, + so that users get the improved performance + of a parallel build without having to specify the option by hand. + A complicating factor is that a good value + for the <literal>-j</literal> option is + somewhat system-dependent. + One rough guideline is that the more processors + your system has, + the higher you want to set the + <literal>-j</literal> value, + in order to take advantage of the number of CPUs. + + </para> + + <para> + + For example, suppose the administrators + of your development systems + have standardized on setting a + <varname>NUM_CPU</varname> environment variable + to the number of processors on each system. + A little bit of Python code + to access the environment variable + and the &SetOption; function + provide the right level of flexibility: + + </para> + + <programlisting> + import os + num_cpu = int(os.environ.get('NUM_CPU', 2)) + SetOption('num_jobs', num_cpu) + print "running with -j", GetOption('num_jobs') + </programlisting> + + <para> + + The above snippet of code + sets the value of the <literal>--jobs</literal> option + to the value specified in the + <varname>$NUM_CPU</varname> environment variable. + (This is one of the exception cases + where the string is spelled differently from + the from command-line option. + The string for fetching or setting the <literal>--jobs</literal> + value is <literal>num_jobs</literal> + for historical reasons.) + The code in this example prints the <literal>num_jobs</literal> + value for illustrative purposes. + It uses a default value of <literal>2</literal> + to provide some minimal parallelism even on + single-processor systems: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + running with -j 2 + scons: `.' is up to date. + </screen> + + <para> + + But if the <varname>$NUM_CPU</varname> + environment variable is set, + then we use that for the default number of jobs: + + </para> + + <screen> + % <userinput>export NUM_CPU="4"</userinput> + % <userinput>scons -Q</userinput> + running with -j 4 + scons: `.' is up to date. + </screen> + + <para> + + But any explicit + <literal>-j</literal> or <literal>--jobs</literal> + value the user specifies an the command line is used first, + regardless of whether or not + the <varname>$NUM_CPU</varname> environment + variable is set: + + </para> + + <screen> + % <userinput>scons -Q -j 7</userinput> + running with -j 7 + scons: `.' is up to date. + % <userinput>export NUM_CPU="4"</userinput> + % <userinput>scons -Q -j 3</userinput> + running with -j 3 + scons: `.' is up to date. + </screen> + + </section> + + <section id="sect-command-line-option-strings"> + <title>Strings for Getting or Setting Values of &SCons; Command-Line Options</title> + + <para> + + The strings that you can pass to the &GetOption; + and &SetOption; functions usually correspond to the + first long-form option name + (beginning with two hyphen characters: <literal>--</literal>), + after replacing any remaining hyphen characters + with underscores. + + </para> + + <para> + + The full list of strings and the variables they + correspond to is as follows: + + </para> + + <informaltable> + <tgroup cols="2" align="left"> + + <thead> + + <row> + <entry>String for &GetOption; and &SetOption;</entry> + <entry>Command-Line Option(s)</entry> + </row> + + </thead> + + <tbody> + + <row> + <entry><literal>cache_debug</literal></entry> + <entry><option>--cache-debug</option></entry> + </row> + + <row> + <entry><literal>cache_disable</literal></entry> + <entry><option>--cache-disable</option></entry> + </row> + + <row> + <entry><literal>cache_force</literal></entry> + <entry><option>--cache-force</option></entry> + </row> + + <row> + <entry><literal>cache_show</literal></entry> + <entry><option>--cache-show</option></entry> + </row> + + <row> + <entry><literal>clean</literal></entry> + <entry><option>-c</option>, + <option>--clean</option>, + <option>--remove</option></entry> + </row> + + <row> + <entry><literal>config</literal></entry> + <entry><option>--config</option></entry> + </row> + + <row> + <entry><literal>directory</literal></entry> + <entry><option>-C</option>, + <option>--directory</option></entry> + </row> + + <row> + <entry><literal>diskcheck</literal></entry> + <entry><option>--diskcheck</option></entry> + </row> + + <row> + <entry><literal>duplicate</literal></entry> + <entry><option>--duplicate</option></entry> + </row> + + <row> + <entry><literal>file</literal></entry> + <entry><option>-f</option>, + <option>--file</option>, + <option>--makefile </option>, + <option>--sconstruct</option></entry> + </row> + + <row> + <entry><literal>help</literal></entry> + <entry><option>-h</option>, + <option>--help</option></entry> + </row> + + <row> + <entry><literal>ignore_errors</literal></entry> + <entry><option>--ignore-errors</option></entry> + </row> + + <row> + <entry><literal>implicit_cache</literal></entry> + <entry><option>--implicit-cache</option></entry> + </row> + + <row> + <entry><literal>implicit_deps_changed</literal></entry> + <entry><option>--implicit-deps-changed</option></entry> + </row> + + <row> + <entry><literal>implicit_deps_unchanged</literal></entry> + <entry><option>--implicit-deps-unchanged</option></entry> + </row> + + <row> + <entry><literal>interactive</literal></entry> + <entry><option>--interact</option>, + <option>--interactive</option></entry> + </row> + + <row> + <entry><literal>keep_going</literal></entry> + <entry><option>-k</option>, + <option>--keep-going</option></entry> + </row> + + <row> + <entry><literal>max_drift</literal></entry> + <entry><option>--max-drift</option></entry> + </row> + + <row> + <entry><literal>no_exec</literal></entry> + <entry><option>-n</option>, + <option>--no-exec</option>, + <option>--just-print</option>, + <option>--dry-run</option>, + <option>--recon</option></entry> + </row> + + <row> + <entry><literal>no_site_dir</literal></entry> + <entry><option>--no-site-dir</option></entry> + </row> + + <row> + <entry><literal>num_jobs</literal></entry> + <entry><option>-j</option>, + <option>--jobs</option></entry> + </row> + + <row> + <entry><literal>profile_file</literal></entry> + <entry><option>--profile</option></entry> + </row> + + <row> + <entry><literal>question</literal></entry> + <entry><option>-q</option>, + <option>--question</option></entry> + </row> + + <row> + <entry><literal>random</literal></entry> + <entry><option>--random</option></entry> + </row> + + <row> + <entry><literal>repository</literal></entry> + <entry><option>-Y</option>, + <option>--repository</option>, + <option>--srcdir</option></entry> + </row> + + <row> + <entry><literal>silent</literal></entry> + <entry><option>-s</option>, + <option>--silent</option>, + <option>--quiet</option></entry> + </row> + + <row> + <entry><literal>site_dir</literal></entry> + <entry><option>--site-dir</option></entry> + </row> + + <row> + <entry><literal>stack_size</literal></entry> + <entry><option>--stack-size</option></entry> + </row> + + <row> + <entry><literal>taskmastertrace_file</literal></entry> + <entry><option>--taskmastertrace</option></entry> + </row> + + <row> + <entry><literal>warn</literal></entry> + <entry><option>--warn</option> <option>--warning</option></entry> + </row> + + </tbody> + + </tgroup> + </informaltable> + + </section> + + <section> + <title>Adding Custom Command-Line Options: the &AddOption; Function</title> + + <para> + + &SCons; also allows you to define your own + command-line options with the &AddOption; function. + The &AddOption; function takes the same arguments + as the <function>optparse.add_option</function> function + from the standard Python library. + <footnote> + <para> + The &AddOption; function is, + in fact, implemented using a subclass + of the <classname>optparse.OptionParser</classname>. + </para> + </footnote> + Once you have added a custom command-line option + with the &AddOption; function, + the value of the option (if any) is immediately available + using the standard &GetOption; function. + (The value can also be set using &SetOption;, + although that's not very useful in practice + because a default value can be specified in + directly in the &AddOption; call.) + + </para> + + <para> + + One useful example of using this functionality + is to provide a <option>--prefix</option> for users: + + </para> + + <programlisting> + AddOption('--prefix', + dest='prefix', + type='string', + nargs=1, + action='store', + metavar='DIR', + help='installation prefix') + + env = Environment(PREFIX = GetOption('prefix')) + + installed_foo = env.Install('$PREFIX/usr/bin', 'foo.in') + Default(installed_foo) + </programlisting> + + <para> + + The above code uses the &GetOption; function + to set the <varname>$PREFIX</varname> + construction variable to any + value that the user specifies with a command-line + option of <literal>--prefix</literal>. + Because <varname>$PREFIX</varname> + will expand to a null string if it's not initialized, + running &SCons; without the + option of <literal>--prefix</literal> + will install the file in the + <filename>/usr/bin/</filename> directory: + + </para> + + <screen> + % <userinput>scons -Q -n</userinput> + Install file: "foo.in" as "/usr/bin/foo.in" + </screen> + + <para> + + But specifying <literal>--prefix=/tmp/install</literal> + on the command line causes the file to be installed in the + <filename>/tmp/install/usr/bin/</filename> directory: + + </para> + + <screen> + % <userinput>scons -Q -n --prefix=/tmp/install</userinput> + Install file: "foo.in" as "/tmp/install/usr/bin/foo.in" + </screen> + + </section> + + </section> + + <section id="sect-command-line-variables"> + <title>Command-Line <varname>variable</varname>=<varname>value</varname> Build Variables</title> + + <para> + + You may want to control various aspects + of your build by allowing the user + to specify <varname>variable</varname>=<varname>value</varname> + values on the command line. + For example, suppose you + want users to be able to + build a debug version of a program + by running &SCons; as follows: + + </para> + + <screen> + % <userinput>scons -Q debug=1</userinput> + </screen> + + <para> + + &SCons; provides an &ARGUMENTS; dictionary + that stores all of the + <varname>variable</varname>=<varname>value</varname> + assignments from the command line. + This allows you to modify + aspects of your build in response + to specifications on the command line. + (Note that unless you want to require + that users <emphasis>always</emphasis> + specify a variable, + you probably want to use + the Python + <literal>ARGUMENTS.get()</literal> function, + which allows you to specify a default value + to be used if there is no specification + on the command line.) + + </para> + + <para> + + The following code sets the &cv-link-CCFLAGS; construction + variable in response to the <varname>debug</varname> + flag being set in the &ARGUMENTS; dictionary: + + </para> + + <programlisting> + env = Environment() + debug = ARGUMENTS.get('debug', 0) + if int(debug): + env.Append(CCFLAGS = '-g') + env.Program('prog.c') + </programlisting> + + <para> + + This results in the <varname>-g</varname> + compiler option being used when + <literal>debug=1</literal> + is used on the command line: + + </para> + + <screen> + % <userinput>scons -Q debug=0</userinput> + cc -o prog.o -c prog.c + cc -o prog prog.o + % <userinput>scons -Q debug=0</userinput> + scons: `.' is up to date. + % <userinput>scons -Q debug=1</userinput> + scons: `.' is up to date. + % <userinput>scons -Q debug=1</userinput> + scons: `.' is up to date. + </screen> + + <para> + + Notice that &SCons; keeps track of + the last values used to build the object files, + and as a result correctly rebuilds + the object and executable files + only when the value of the <literal>debug</literal> + argument has changed. + + </para> + + <para> + + The &ARGUMENTS; dictionary has two minor drawbacks. + First, because it is a dictionary, + it can only store one value for each specified keyword, + and thus only "remembers" the last setting + for each keyword on the command line. + This makes the &ARGUMENTS; dictionary + inappropriate if users should be able to + specify multiple values + on the command line for a given keyword. + Second, it does not preserve + the order in which the variable settings + were specified, + which is a problem if + you want the configuration to + behave differently in response + to the order in which the build + variable settings were specified on the command line. + + </para> + + <para> + + To accomodate these requirements, + &SCons; provides an &ARGLIST; variable + that gives you direct access to + <varname>variable</varname>=<varname>value</varname> + settings on the command line, + in the exact order they were specified, + and without removing any duplicate settings. + Each element in the &ARGLIST; variable + is itself a two-element list + containing the keyword and the value + of the setting, + and you must loop through, + or otherwise select from, + the elements of &ARGLIST; to + process the specific settings you want + in whatever way is appropriate for your configuration. + For example, + the following code to let the user + add to the &CPPDEFINES; construction variable + by specifying multiple + <varname>define=</varname> + settings on the command line: + + </para> + + <programlisting> + cppdefines = [] + for key, value in ARGLIST: + if key == 'define': + cppdefines.append(value) + env = Environment(CPPDEFINES = cppdefines) + env.Object('prog.c') + </programlisting> + + <para> + + Yields the following output: + + </para> + + <screen> + % <userinput>scons -Q define=FOO</userinput> + cc -o prog.o -c -DFOO prog.c + % <userinput>scons -Q define=FOO define=BAR</userinput> + scons: `.' is up to date. + </screen> + + <para> + + Note that the &ARGLIST; and &ARGUMENTS; + variables do not interfere with each other, + but merely provide slightly different views + into how the user specified + <varname>variable</varname>=<varname>value</varname> + settings on the command line. + You can use both variables in the same + &SCons; configuration. + In general, the &ARGUMENTS; dictionary + is more convenient to use, + (since you can just fetch variable + settings through a dictionary access), + and the &ARGLIST; list + is more flexible + (since you can examine the + specific order in which + the user's command-line variabe settings). + + </para> + + <section> + <title>Controlling Command-Line Build Variables</title> + + <para> + + Being able to use a command-line build variable like + <literal>debug=1</literal> is handy, + but it can be a chore to write specific Python code + to recognize each such variable, + check for errors and provide appropriate messages, + and apply the values to a construction variable. + To help with this, + &SCons; supports a class to + define such build variables easily, + and a mechanism to apply the + build variables to a construction environment. + This allows you to control how the build variables affect + construction environments. + + </para> + + <para> + + For example, suppose that you want users to set + a &RELEASE; construction variable on the + command line whenever the time comes to build + a program for release, + and that the value of this variable + should be added to the command line + with the appropriate <literal>-D</literal> option + (or other command line option) + to pass the value to the C compiler. + Here's how you might do that by setting + the appropriate value in a dictionary for the + &cv-link-CPPDEFINES; construction variable: + + </para> + + <programlisting> + vars = Variables() + vars.Add('RELEASE', 'Set to 1 to build for release', 0) + env = Environment(variables = vars, + CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) + env.Program(['foo.c', 'bar.c']) + </programlisting> + + <para> + + This &SConstruct; file first creates a &Variables; object + (the <literal>vars = Variables()</literal> call), + and then uses the object's &Add; + method to indicate that the &RELEASE; + variable can be set on the command line, + and that its default value will be <literal>0</literal> + (the third argument to the &Add; method). + The second argument is a line of help text; + we'll learn how to use it in the next section. + + </para> + + <para> + + We then pass the created &Variables; + object as a &variables; keyword argument + to the &Environment; call + used to create the construction environment. + This then allows a user to set the + &RELEASE; build variable on the command line + and have the variable show up in + the command line used to build each object from + a C source file: + + </para> + + <screen> + % <userinput>scons -Q RELEASE=1</userinput> + cc -o bar.o -c -DRELEASE_BUILD=1 bar.c + cc -o foo.o -c -DRELEASE_BUILD=1 foo.c + cc -o foo foo.o bar.o + </screen> + + <para> + + NOTE: Before &SCons; release 0.98.1, these build variables + were known as "command-line build options." + The class was actually named the &Options; class, + and in the sections below, + the various functions were named + &BoolOption;, &EnumOption;, &ListOption;, + &PathOption;, &PackageOption; and &AddOptions;. + These older names still work, + and you may encounter them in older + &SConscript; fles, + but their use is discouraged + and will be officially deprecated some day. + + </para> + + </section> + + <section> + <title>Providing Help for Command-Line Build Variables</title> + + <para> + + To make command-line build variables most useful, + you ideally want to provide + some help text that will describe + the available variables + when the user runs <literal>scons -h</literal>. + You could write this text by hand, + but &SCons; provides an easier way. + &Variables; objects support a + &GenerateHelpText; method + that will, as its name suggests, + generate text that describes + the various variables that + have been added to it. + You then pass the output from this method to + the &Help; function: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add('RELEASE', 'Set to 1 to build for release', 0) + env = Environment(variables = vars) + Help(vars.GenerateHelpText(env)) + </programlisting> + + <para> + + &SCons; will now display some useful text + when the <literal>-h</literal> option is used: + + </para> + + <screen> + % <userinput>scons -Q -h</userinput> + + RELEASE: Set to 1 to build for release + default: 0 + actual: 0 + + Use scons -H for help about command-line options. + </screen> + + <para> + + Notice that the help output shows the default value, + and the current actual value of the build variable. + + </para> + + </section> + + <section> + <title>Reading Build Variables From a File</title> + + <para> + + Giving the user a way to specify the + value of a build variable on the command line + is useful, + but can still be tedious + if users must specify the variable + every time they run &SCons;. + We can let users provide customized build variable settings + in a local file by providing a + file name when we create the + &Variables; object: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add('RELEASE', 'Set to 1 to build for release', 0) + env = Environment(variables = vars, + CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) + env.Program(['foo.c', 'bar.c']) + Help(vars.GenerateHelpText(env)) + </programlisting> + + <para> + + This then allows the user to control the &RELEASE; + variable by setting it in the &custom_py; file: + + </para> + + <programlisting> + RELEASE = 1 + </programlisting> + + <para> + + Note that this file is actually executed + like a Python script. + Now when we run &SCons;: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o bar.o -c -DRELEASE_BUILD=1 bar.c + cc -o foo.o -c -DRELEASE_BUILD=1 foo.c + cc -o foo foo.o bar.o + </screen> + + <para> + + And if we change the contents of &custom_py; to: + + </para> + + <programlisting> + RELEASE = 0 + </programlisting> + + <para> + + The object files are rebuilt appropriately + with the new variable: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o bar.o -c -DRELEASE_BUILD=0 bar.c + cc -o foo.o -c -DRELEASE_BUILD=0 foo.c + cc -o foo foo.o bar.o + </screen> + + </section> + + <section> + <title>Pre-Defined Build Variable Functions</title> + + <para> + + &SCons; provides a number of functions + that provide ready-made behaviors + for various types of command-line build variables. + + </para> + + <section> + <title>True/False Values: the &BoolVariable; Build Variable Function</title> + + <para> + + It's often handy to be able to specify a + variable that controls a simple Boolean variable + with a &true; or &false; value. + It would be even more handy to accomodate + users who have different preferences for how to represent + &true; or &false; values. + The &BoolVariable; function + makes it easy to accomodate these + common representations of + &true; or &false;. + + </para> + + <para> + + The &BoolVariable; function takes three arguments: + the name of the build variable, + the default value of the build variable, + and the help string for the variable. + It then returns appropriate information for + passing to the &Add; method of a &Variables; object, like so: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add(BoolVariable('RELEASE', 'Set to build for release', 0)) + env = Environment(variables = vars, + CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) + env.Program('foo.c') + </programlisting> + + <para> + + With this build variable, + the &RELEASE; variable can now be enabled by + setting it to the value <literal>yes</literal> + or <literal>t</literal>: + + </para> + + <screen> + % <userinput>scons -Q RELEASE=yes foo.o</userinput> + cc -o foo.o -c -DRELEASE_BUILD=True foo.c + </screen> + + <screen> + % <userinput>scons -Q RELEASE=t foo.o</userinput> + cc -o foo.o -c -DRELEASE_BUILD=True foo.c + </screen> + + <para> + + Other values that equate to &true; include + <literal>y</literal>, + <literal>1</literal>, + <literal>on</literal> + and + <literal>all</literal>. + + </para> + + <para> + + Conversely, &RELEASE; may now be given a &false; + value by setting it to + <literal>no</literal> + or + <literal>f</literal>: + + </para> + + <screen> + % <userinput>scons -Q RELEASE=no foo.o</userinput> + cc -o foo.o -c -DRELEASE_BUILD=False foo.c + </screen> + + <screen> + % <userinput>scons -Q RELEASE=f foo.o</userinput> + cc -o foo.o -c -DRELEASE_BUILD=False foo.c + </screen> + + <para> + + Other values that equate to &false; include + <literal>n</literal>, + <literal>0</literal>, + <literal>off</literal> + and + <literal>none</literal>. + + </para> + + <para> + + Lastly, if a user tries to specify + any other value, + &SCons; supplies an appropriate error message: + + </para> + + <screen> + % <userinput>scons -Q RELEASE=bad_value foo.o</userinput> + + scons: *** Error converting option: RELEASE + Invalid value for boolean option: bad_value + File "/home/my/project/SConstruct", line 4, in ? + </screen> + + </section> + + <section> + <title>Single Value From a List: the &EnumVariable; Build Variable Function</title> + + <para> + + Suppose that we want a user to be able to + set a &COLOR; variable + that selects a background color to be + displayed by an application, + but that we want to restrict the + choices to a specific set of allowed colors. + This can be set up quite easily + using the &EnumVariable;, + which takes a list of &allowed_values + in addition to the variable name, + default value, + and help text arguments: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add(EnumVariable('COLOR', 'Set background color', 'red', + allowed_values=('red', 'green', 'blue'))) + env = Environment(variables = vars, + CPPDEFINES={'COLOR' : '"${COLOR}"'}) + env.Program('foo.c') + </programlisting> + + <para> + + The user can now explicity set the &COLOR; build variable + to any of the specified allowed values: + + </para> + + <screen> + % <userinput>scons -Q COLOR=red foo.o</userinput> + cc -o foo.o -c -DCOLOR="red" foo.c + % <userinput>scons -Q COLOR=blue foo.o</userinput> + scons: `foo.o' is up to date. + % <userinput>scons -Q COLOR=green foo.o</userinput> + scons: `foo.o' is up to date. + </screen> + + <para> + + But, almost more importantly, + an attempt to set &COLOR; + to a value that's not in the list + generates an error message: + + </para> + + <screen> + % <userinput>scons -Q COLOR=magenta foo.o</userinput> + + scons: *** Invalid value for option COLOR: magenta + File "/home/my/project/SConstruct", line 5, in ? + </screen> + + <para> + + The &EnumVariable; function also supports a way + to map alternate names to allowed values. + Suppose, for example, + that we want to allow the user + to use the word <literal>navy</literal> as a synonym for + <literal>blue</literal>. + We do this by adding a ↦ dictionary + that will map its key values + to the desired legal value: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add(EnumVariable('COLOR', 'Set background color', 'red', + allowed_values=('red', 'green', 'blue'), + map={'navy':'blue'})) + env = Environment(variables = vars, + CPPDEFINES={'COLOR' : '"${COLOR}"'}) + env.Program('foo.c') + </programlisting> + + <para> + + As desired, the user can then use + <literal>navy</literal> on the command line, + and &SCons; will translate it into <literal>blue</literal> + when it comes time to use the &COLOR; + variable to build a target: + + </para> + + <screen> + % <userinput>scons -Q COLOR=navy foo.o</userinput> + cc -o foo.o -c -DCOLOR="blue" foo.c + </screen> + + <para> + + By default, when using the &EnumVariable; function, + arguments that differ + from the legal values + only in case + are treated as illegal values: + + </para> + + <screen> + % <userinput>scons -Q COLOR=Red foo.o</userinput> + + scons: *** Invalid value for option COLOR: Red + File "/home/my/project/SConstruct", line 5, in ? + % <userinput>scons -Q COLOR=BLUE foo.o</userinput> + + scons: *** Invalid value for option COLOR: BLUE + File "/home/my/project/SConstruct", line 5, in ? + % <userinput>scons -Q COLOR=nAvY foo.o</userinput> + + scons: *** Invalid value for option COLOR: nAvY + File "/home/my/project/SConstruct", line 5, in ? + </screen> + + <para> + + The &EnumVariable; function can take an additional + &ignorecase; keyword argument that, + when set to <literal>1</literal>, + tells &SCons; to allow case differences + when the values are specified: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add(EnumVariable('COLOR', 'Set background color', 'red', + allowed_values=('red', 'green', 'blue'), + map={'navy':'blue'}, + ignorecase=1)) + env = Environment(variables = vars, + CPPDEFINES={'COLOR' : '"${COLOR}"'}) + env.Program('foo.c') + </programlisting> + + <para> + + Which yields the output: + + </para> + + <screen> + % <userinput>scons -Q COLOR=Red foo.o</userinput> + cc -o foo.o -c -DCOLOR="Red" foo.c + % <userinput>scons -Q COLOR=BLUE foo.o</userinput> + scons: `foo.o' is up to date. + % <userinput>scons -Q COLOR=nAvY foo.o</userinput> + scons: `foo.o' is up to date. + % <userinput>scons -Q COLOR=green foo.o</userinput> + scons: `foo.o' is up to date. + </screen> + + <para> + + Notice that an &ignorecase; value of <literal>1</literal> + preserves the case-spelling that the user supplied. + If you want &SCons; to translate the names + into lower-case, + regardless of the case used by the user, + specify an &ignorecase; value of <literal>2</literal>: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add(EnumVariable('COLOR', 'Set background color', 'red', + allowed_values=('red', 'green', 'blue'), + map={'navy':'blue'}, + ignorecase=2)) + env = Environment(variables = vars, + CPPDEFINES={'COLOR' : '"${COLOR}"'}) + env.Program('foo.c') + </programlisting> + + <para> + + Now &SCons; will use values of + <literal>red</literal>, + <literal>green</literal> or + <literal>blue</literal> + regardless of how the user spells + those values on the command line: + + </para> + + <screen> + % <userinput>scons -Q COLOR=Red foo.o</userinput> + cc -o foo.o -c -DCOLOR="red" foo.c + % <userinput>scons -Q COLOR=nAvY foo.o</userinput> + scons: `foo.o' is up to date. + % <userinput>scons -Q COLOR=GREEN foo.o</userinput> + scons: `foo.o' is up to date. + </screen> + + </section> + + <section> + <title>Multiple Values From a List: the &ListVariable; Build Variable Function</title> + + <para> + + Another way in which you might want to allow users + to control a build variable is to + specify a list of one or more legal values. + &SCons; supports this through the &ListVariable; function. + If, for example, we want a user to be able to set a + &COLORS; variable to one or more of the legal list of values: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add(ListVariable('COLORS', 'List of colors', 0, + ['red', 'green', 'blue'])) + env = Environment(variables = vars, + CPPDEFINES={'COLORS' : '"${COLORS}"'}) + env.Program('foo.c') + </programlisting> + + <para> + + A user can now specify a comma-separated list + of legal values, + which will get translated into a space-separated + list for passing to the any build commands: + + </para> + + <screen> + % <userinput>scons -Q COLORS=red,blue foo.o</userinput> + cc -o foo.o -c -DCOLORS="red blue" foo.c + % <userinput>scons -Q COLORS=blue,green,red foo.o</userinput> + scons: `foo.o' is up to date. + </screen> + + <para> + + In addition, the &ListVariable; function + allows the user to specify explicit keywords of + &all; or &none; + to select all of the legal values, + or none of them, respectively: + + </para> + + <screen> + % <userinput>scons -Q COLORS=all foo.o</userinput> + cc -o foo.o -c -DCOLORS="red green blue" foo.c + % <userinput>scons -Q COLORS=none foo.o</userinput> + scons: `foo.o' is up to date. + </screen> + + <para> + + And, of course, an illegal value + still generates an error message: + + </para> + + <screen> + % <userinput>scons -Q COLORS=magenta foo.o</userinput> + + scons: *** Error converting option: COLORS + Invalid value(s) for option: magenta + File "/home/my/project/SConstruct", line 5, in ? + </screen> + + </section> + + <section> + <title>Path Names: the &PathVariable; Build Variable Function</title> + + <para> + + &SCons; supports a &PathVariable; function + to make it easy to create a build variable + to control an expected path name. + If, for example, you need to + define a variable in the preprocessor + that controls the location of a + configuration file: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add(PathVariable('CONFIG', + 'Path to configuration file', + '/etc/my_config')) + env = Environment(variables = vars, + CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'}) + env.Program('foo.c') + </programlisting> + + <para> + + This then allows the user to + override the &CONFIG; build variable + on the command line as necessary: + + </para> + + <screen> + % <userinput>scons -Q foo.o</userinput> + cc -o foo.o -c -DCONFIG_FILE="/etc/my_config" foo.c + % <userinput>scons -Q CONFIG=/usr/local/etc/other_config foo.o</userinput> + scons: `foo.o' is up to date. + </screen> + + <para> + + By default, &PathVariable; checks to make sure + that the specified path exists and generates an error if it + doesn't: + + </para> + + <screen> + % <userinput>scons -Q CONFIG=/does/not/exist foo.o</userinput> + + scons: *** Path for option CONFIG does not exist: /does/not/exist + File "/home/my/project/SConstruct", line 6, in ? + </screen> + + <para> + + &PathVariable; provides a number of methods + that you can use to change this behavior. + If you want to ensure that any specified paths are, + in fact, files and not directories, + use the &PathVariable_PathIsFile; method: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add(PathVariable('CONFIG', + 'Path to configuration file', + '/etc/my_config', + PathVariable.PathIsFile)) + env = Environment(variables = vars, + CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'}) + env.Program('foo.c') + </programlisting> + + <para> + + Conversely, to ensure that any specified paths are + directories and not files, + use the &PathVariable_PathIsDir; method: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add(PathVariable('DBDIR', + 'Path to database directory', + '/var/my_dbdir', + PathVariable.PathIsDir)) + env = Environment(variables = vars, + CPPDEFINES={'DBDIR' : '"$DBDIR"'}) + env.Program('foo.c') + </programlisting> + + <para> + + If you want to make sure that any specified paths + are directories, + and you would like the directory created + if it doesn't already exist, + use the &PathVariable_PathIsDirCreate; method: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add(PathVariable('DBDIR', + 'Path to database directory', + '/var/my_dbdir', + PathVariable.PathIsDirCreate)) + env = Environment(variables = vars, + CPPDEFINES={'DBDIR' : '"$DBDIR"'}) + env.Program('foo.c') + </programlisting> + + <para> + + Lastly, if you don't care whether the path exists, + is a file, or a directory, + use the &PathVariable_PathAccept; method + to accept any path that the user supplies: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add(PathVariable('OUTPUT', + 'Path to output file or directory', + None, + PathVariable.PathAccept)) + env = Environment(variables = vars, + CPPDEFINES={'OUTPUT' : '"$OUTPUT"'}) + env.Program('foo.c') + </programlisting> + + </section> + + <section> + <title>Enabled/Disabled Path Names: the &PackageVariable; Build Variable Function</title> + + <para> + + Sometimes you want to give users + even more control over a path name variable, + allowing them to explicitly enable or + disable the path name + by using <literal>yes</literal> or <literal>no</literal> keywords, + in addition to allow them + to supply an explicit path name. + &SCons; supports the &PackageVariable; + function to support this: + + </para> + + <programlisting> + vars = Variables('custom.py') + vars.Add(PackageVariable('PACKAGE', + 'Location package', + '/opt/location')) + env = Environment(variables = vars, + CPPDEFINES={'PACKAGE' : '"$PACKAGE"'}) + env.Program('foo.c') + </programlisting> + + <para> + + When the &SConscript; file uses the &PackageVariable; funciton, + user can now still use the default + or supply an overriding path name, + but can now explicitly set the + specified variable to a value + that indicates the package should be enabled + (in which case the default should be used) + or disabled: + + </para> + + <screen> + % <userinput>scons -Q foo.o</userinput> + cc -o foo.o -c -DPACKAGE="/opt/location" foo.c + % <userinput>scons -Q PACKAGE=/usr/local/location foo.o</userinput> + scons: `foo.o' is up to date. + % <userinput>scons -Q PACKAGE=yes foo.o</userinput> + scons: `foo.o' is up to date. + % <userinput>scons -Q PACKAGE=no foo.o</userinput> + scons: `foo.o' is up to date. + </screen> + + </section> + + </section> + + <section> + <title>Adding Multiple Command-Line Build Variables at Once</title> + + <para> + + Lastly, &SCons; provides a way to add + multiple build variables to a &Variables; object at once. + Instead of having to call the &Add; method + multiple times, + you can call the &AddVariables; + method with a list of build variables + to be added to the object. + Each build variable is specified + as either a tuple of arguments, + just like you'd pass to the &Add; method itself, + or as a call to one of the pre-defined + functions for pre-packaged command-line build variables. + in any order: + + </para> + + <programlisting> + vars = Variables() + vars.AddVariables( + ('RELEASE', 'Set to 1 to build for release', 0), + ('CONFIG', 'Configuration file', '/etc/my_config'), + BoolVariable('warnings', 'compilation with -Wall and similiar', 1), + EnumVariable('debug', 'debug output and symbols', 'no', + allowed_values=('yes', 'no', 'full'), + map={}, ignorecase=0), # case sensitive + ListVariable('shared', + 'libraries to build as shared libraries', + 'all', + names = list_of_libs), + PackageVariable('x11', + 'use X11 installed here (yes = search some places)', + 'yes'), + PathVariable('qtdir', 'where the root of Qt is installed', qtdir), + ) + </programlisting> + + <para> + </para> + + </section> + + <section> + <title>Handling Unknown Command-Line Build Variables: the &UnknownVariables; Function</title> + + <para> + + Users may, of course, + occasionally misspell variable names in their command-line settings. + &SCons; does not generate an error or warning + for any unknown variables the users specifies on the command line. + (This is in no small part because you may be + processing the arguments directly using the &ARGUMENTS; dictionary, + and therefore &SCons; can't know in the general case + whether a given "misspelled" variable is + really unknown and a potential problem, + or something that your &SConscript; file + will handle directly with some Python code.) + + </para> + + <para> + + If, however, you're using a &Variables; object to + define a specific set of command-line build variables + that you expect users to be able to set, + you may want to provide an error + message or warning of your own + if the user supplies a variable setting + that is <emphasis>not</emphasis> among + the defined list of variable names known to the &Variables; object. + You can do this by calling the &UnknownVariables; + method of the &Variables; object: + + </para> + + <programlisting> + vars = Variables(None) + vars.Add('RELEASE', 'Set to 1 to build for release', 0) + env = Environment(variables = vars, + CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) + unknown = vars.UnknownVariables() + if unknown: + print "Unknown variables:", unknown.keys() + Exit(1) + env.Program('foo.c') + </programlisting> + + <para> + + The &UnknownVariables; method returns a dictionary + containing the keywords and values + of any variables the user specified on the command line + that are <emphasis>not</emphasis> + among the variables known to the &Variables; object + (from having been specified using + the &Variables; object's&Add; method). + In the examble above, + we check for whether the dictionary + returned by the &UnknownVariables; is non-empty, + and if so print the Python list + containing the names of the unknwown variables + and then call the &Exit; function + to terminate &SCons;: + + </para> + + <screen> + % <userinput>scons -Q NOT_KNOWN=foo</userinput> + Unknown variables: ['NOT_KNOWN'] + </screen> + + <para> + + Of course, you can process the items in the + dictionary returned by the &UnknownVariables; function + in any way appropriate to your build configuration, + including just printing a warning message + but not exiting, + logging an error somewhere, + etc. + + </para> + + <para> + + Note that you must delay the call of &UnknownVariables; + until after you have applied the &Variables; object + to a construction environment + with the <literal>variables=</literal> + keyword argument of an &Environment; call. + + </para> + + </section> + + </section> + + <section id="sect-command-line-targets"> + <title>Command-Line Targets</title> + + <section> + <title>Fetching Command-Line Targets: the &COMMAND_LINE_TARGETS; Variable</title> + + <para> + + &SCons; supports a &COMMAND_LINE_TARGETS; variable + that lets you fetch the list of targets that the + user specified on the command line. + You can use the targets to manipulate the + build in any way you wish. + As a simple example, + suppose that you want to print a reminder + to the user whenever a specific program is built. + You can do this by checking for the + target in the &COMMAND_LINE_TARGETS; list: + + </para> + + <programlisting> + if 'bar' in COMMAND_LINE_TARGETS: + print "Don't forget to copy `bar' to the archive!" + Default(Program('foo.c')) + Program('bar.c') + </programlisting> + + <para> + + Then, running &SCons; with the default target + works as it always does, + but explicity specifying the &bar; target + on the command line generates the warning message: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o foo.o -c foo.c + cc -o foo foo.o + % <userinput>scons -Q bar</userinput> + Don't forget to copy `bar' to the archive! + cc -o bar.o -c bar.c + cc -o bar bar.o + </screen> + + <para> + + Another practical use for the &COMMAND_LINE_TARGETS; variable + might be to speed up a build + by only reading certain subsidiary &SConscript; + files if a specific target is requested. + + </para> + + </section> + + <section> + <title>Controlling the Default Targets: the &Default; Function</title> + + <para> + + One of the most basic things you can control + is which targets &SCons; will build by default--that is, + when there are no targets specified on the command line. + As mentioned previously, + &SCons; will normally build every target + in or below the current directory + by default--that is, when you don't + explicitly specify one or more targets + on the command line. + Sometimes, however, you may want + to specify explicitly that only + certain programs, or programs in certain directories, + should be built by default. + You do this with the &Default; function: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.Program('goodbye.c') + Default(hello) + </programlisting> + + <para> + + This &SConstruct; file knows how to build two programs, + &hello; and &goodbye;, + but only builds the + &hello; program by default: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q</userinput> + scons: `hello' is up to date. + % <userinput>scons -Q goodbye</userinput> + cc -o goodbye.o -c goodbye.c + cc -o goodbye goodbye.o + </screen> + + <para> + + Note that, even when you use the &Default; + function in your &SConstruct; file, + you can still explicitly specify the current directory + (<literal>.</literal>) on the command line + to tell &SCons; to build + everything in (or below) the current directory: + + </para> + + <screen> + % <userinput>scons -Q .</userinput> + cc -o goodbye.o -c goodbye.c + cc -o goodbye goodbye.o + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + <para> + + You can also call the &Default; + function more than once, + in which case each call + adds to the list of targets to be built by default: + + </para> + + <programlisting> + env = Environment() + prog1 = env.Program('prog1.c') + Default(prog1) + prog2 = env.Program('prog2.c') + prog3 = env.Program('prog3.c') + Default(prog3) + </programlisting> + + <para> + + Or you can specify more than one target + in a single call to the &Default; function: + + </para> + + <programlisting> + env = Environment() + prog1 = env.Program('prog1.c') + prog2 = env.Program('prog2.c') + prog3 = env.Program('prog3.c') + Default(prog1, prog3) + </programlisting> + + <para> + + Either of these last two examples + will build only the + <application>prog1</application> + and + <application>prog3</application> + programs by default: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o prog1.o -c prog1.c + cc -o prog1 prog1.o + cc -o prog3.o -c prog3.c + cc -o prog3 prog3.o + % <userinput>scons -Q .</userinput> + cc -o prog2.o -c prog2.c + cc -o prog2 prog2.o + </screen> + + <para> + + You can list a directory as + an argument to &Default;: + + </para> + + <programlisting> + env = Environment() + env.Program(['prog1/main.c', 'prog1/foo.c']) + env.Program(['prog2/main.c', 'prog2/bar.c']) + Default('prog1') + </programlisting> + + <para> + + In which case only the target(s) in that + directory will be built by default: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o prog1/foo.o -c prog1/foo.c + cc -o prog1/main.o -c prog1/main.c + cc -o prog1/main prog1/main.o prog1/foo.o + % <userinput>scons -Q</userinput> + scons: `prog1' is up to date. + % <userinput>scons -Q .</userinput> + cc -o prog2/bar.o -c prog2/bar.c + cc -o prog2/main.o -c prog2/main.c + cc -o prog2/main prog2/main.o prog2/bar.o + </screen> + + <para> + + Lastly, if for some reason you don't want + any targets built by default, + you can use the Python <literal>None</literal> + variable: + + </para> + + <programlisting> + env = Environment() + prog1 = env.Program('prog1.c') + prog2 = env.Program('prog2.c') + Default(None) + </programlisting> + + <para> + + Which would produce build output like: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + scons: *** No targets specified and no Default() targets found. Stop. + % <userinput>scons -Q .</userinput> + cc -o prog1.o -c prog1.c + cc -o prog1 prog1.o + cc -o prog2.o -c prog2.c + cc -o prog2 prog2.o + </screen> + + <section> + <title>Fetching the List of Default Targets: the &DEFAULT_TARGETS; Variable</title> + + <para> + + &SCons; supports a &DEFAULT_TARGETS; variable + that lets you get at the current list of default targets. + The &DEFAULT_TARGETS variable has + two important differences from the &COMMAND_LINE_TARGETS; variable. + First, the &DEFAULT_TARGETS; variable is a list of + internal &SCons; nodes, + so you need to convert the list elements to strings + if you want to print them or look for a specific target name. + Fortunately, you can do this easily + by using the Python <function>map</function> function + to run the list through <function>str</function>: + + </para> + + <programlisting> + prog1 = Program('prog1.c') + Default(prog1) + print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS) + </programlisting> + + <para> + + (Keep in mind that all of the manipulation of the + &DEFAULT_TARGETS; list takes place during the + first phase when &SCons; is reading up the &SConscript; files, + which is obvious if + we leave off the <literal>-Q</literal> flag when we run &SCons;:) + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + DEFAULT_TARGETS is ['prog1'] + scons: done reading SConscript files. + scons: Building targets ... + cc -o prog1.o -c prog1.c + cc -o prog1 prog1.o + scons: done building targets. + </screen> + + <para> + + Second, + the contents of the &DEFAULT_TARGETS; list change + in response to calls to the &Default;: function, + as you can see from the following &SConstruct; file: + + </para> + + <programlisting> + prog1 = Program('prog1.c') + Default(prog1) + print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS) + prog2 = Program('prog2.c') + Default(prog2) + print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS) + </programlisting> + + <para> + + Which yields the output: + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + DEFAULT_TARGETS is now ['prog1'] + DEFAULT_TARGETS is now ['prog1', 'prog2'] + scons: done reading SConscript files. + scons: Building targets ... + cc -o prog1.o -c prog1.c + cc -o prog1 prog1.o + cc -o prog2.o -c prog2.c + cc -o prog2 prog2.o + scons: done building targets. + </screen> + + <para> + + In practice, this simply means that you + need to pay attention to the order in + which you call the &Default; function + and refer to the &DEFAULT_TARGETS; list, + to make sure that you don't examine the + list before you've added the default targets + you expect to find in it. + + </para> + + </section> + + </section> + + <section> + <title>Fetching the List of Build Targets, Regardless of Origin: the &BUILD_TARGETS; Variable</title> + + <para> + + We've already been introduced to the + &COMMAND_LINE_TARGETS; variable, + which contains a list of targets specified on the command line, + and the &DEFAULT_TARGETS; variable, + which contains a list of targets specified + via calls to the &Default; method or function. + Sometimes, however, + you want a list of whatever targets + &SCons; will try to build, + regardless of whether the targets came from the + command line or a &Default; call. + You could code this up by hand, as follows: + + </para> + + <programlisting> + if COMMAND_LINE_TARGETS: + targets = COMMAND_LINE_TARGETS + else: + targets = DEFAULT_TARGETS + </programlisting> + + <para> + + &SCons;, however, provides a convenient + &BUILD_TARGETS; variable + that eliminates the need for this by-hand manipulation. + Essentially, the &BUILD_TARGETS; variable + contains a list of the command-line targets, + if any were specified, + and if no command-line targets were specified, + it contains a list of the targets specified + via the &Default; method or function. + + </para> + + <para> + + Because &BUILD_TARGETS; may contain a list of &SCons; nodes, + you must convert the list elements to strings + if you want to print them or look for a specific target name, + just like the &DEFAULT_TARGETS; list: + + </para> + + <programlisting> + prog1 = Program('prog1.c') + Program('prog2.c') + Default(prog1) + print "BUILD_TARGETS is", map(str, BUILD_TARGETS) + </programlisting> + + <para> + + Notice how the value of &BUILD_TARGETS; + changes depending on whether a target is + specified on the command line: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + BUILD_TARGETS is ['prog1'] + cc -o prog1.o -c prog1.c + cc -o prog1 prog1.o + % <userinput>scons -Q prog2</userinput> + BUILD_TARGETS is ['prog2'] + cc -o prog2.o -c prog2.c + cc -o prog2 prog2.o + % <userinput>scons -Q -c .</userinput> + BUILD_TARGETS is ['.'] + Removed prog1.o + Removed prog1 + Removed prog2.o + Removed prog2 + </screen> + + </section> + + </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/copyright.in b/doc/user/copyright.in new file mode 100644 index 0000000..341698d --- /dev/null +++ b/doc/user/copyright.in @@ -0,0 +1,32 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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. + +--> + +<blockquote> + <para> + + SCons User's Guide Copyright (c) 2004, 2005, 2006, 2007 Steven Knight + + </para> +</blockquote> diff --git a/doc/user/copyright.xml b/doc/user/copyright.xml new file mode 100644 index 0000000..341698d --- /dev/null +++ b/doc/user/copyright.xml @@ -0,0 +1,32 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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. + +--> + +<blockquote> + <para> + + SCons User's Guide Copyright (c) 2004, 2005, 2006, 2007 Steven Knight + + </para> +</blockquote> diff --git a/doc/user/depends.in b/doc/user/depends.in new file mode 100644 index 0000000..dfd52e3 --- /dev/null +++ b/doc/user/depends.in @@ -0,0 +1,1816 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + So far we've seen how &SCons; handles one-time builds. + But one of the main functions of a build tool like &SCons; + is to rebuild only what is necessary + when source files change--or, put another way, + &SCons; should <emphasis>not</emphasis> + waste time rebuilding things that don't need to be rebuilt. + You can see this at work simply by re-invoking &SCons; + after building our simple &hello; example: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct"> + Program('hello.c') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <scons_output example="ex1" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + The second time it is executed, + &SCons; realizes 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> + + <scons_output example="ex1" os="posix"> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + + <para> + + Note that &SCons; reports <literal>"...is up to date"</literal> + only for target files named explicitly on the command line, + to avoid cluttering the output. + + </para> + + <section> + <title>Deciding When an Input File Has Changed: the &Decider; Function</title> + + <para> + + Another aspect of avoiding unnecessary rebuilds + is the fundamental build tool behavior + of <emphasis>rebuilding</emphasis> + things when an input file changes, + so that the built software is up to date. + By default, + &SCons; keeps track of this through an + MD5 &signature;, or checksum, of the contents of each file, + although you can easily configure + &SCons; to use the + modification times (or time stamps) + instead. + You can even specify your own Python function + for deciding if an input file has changed. + + </para> + + <section> + <title>Using MD5 Signatures to Decide if a File Has Changed</title> + + <para> + + By default, + &SCons; keeps track of whether a file has changed + based on an MD5 checksum of the file's contents, + not the file's modification time. + This means that you may be surprised by the + default &SCons; behavior if you are used to the + &Make; convention of forcing + a rebuild by updating the file's modification time + (using the &touch; command, for example): + + </para> + + <scons_output example="ex1" os="posix"> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command>touch hello.c</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + + <para> + + Even though the file's modification time has changed, + &SCons; realizes that the contents of the + &hello_c; file have <emphasis>not</emphasis> changed, + and therefore that the &hello; program + need not be rebuilt. + This avoids unnecessary rebuilds when, + for example, someone rewrites the + contents of a file without making a change. + But if the contents of the file really do change, + then &SCons; detects the change + and rebuilds the program as required: + + </para> + + <scons_output example="ex1" os="posix"> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command output=" [CHANGE THE CONTENTS OF hello.c]">edit hello.c</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + + <para> + + Note that you can, if you wish, + specify this default behavior + (MD5 signatures) explicitly + using the &Decider; function as follows: + + </para> + + <sconstruct> + Program('hello.c') + Decider('MD5') + </sconstruct> + + <para> + + You can also use the string <literal>'content'</literal> + as a synonym for <literal>'MD5'</literal> + when calling the &Decider; function. + + </para> + + <section> + <title>Ramifications of Using MD5 Signatures</title> + + <para> + + Using MD5 signatures to decide if an input file has changed + has one surprising benefit: + if a source file has been changed + in such a way that the contents of the + rebuilt target file(s) + will be exactly the same as the last time + the file was built, + then any "downstream" target files + that depend on the rebuilt-but-not-changed target + file actually need not be rebuilt. + + </para> + + <para> + + So if, for example, + a user were to only change a comment in a &hello_c; file, + then the rebuilt &hello_o; file + would be exactly the same as the one previously built + (assuming the compiler doesn't put any build-specific + information in the object file). + &SCons; would then realize that it would not + need to rebuild the &hello; program as follows: + + </para> + + <scons_output example="ex1" os="posix"> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command output=" [CHANGE A COMMENT IN hello.c]" edit="STRIP CCCOM line">edit hello.c</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + + <para> + + In essence, &SCons; + "short-circuits" any dependent builds + when it realizes that a target file + has been rebuilt to exactly the same file as the last build. + This does take some extra processing time + to read the contents of the target (&hello_o;) file, + but often saves time when the rebuild that was avoided + would have been time-consuming and expensive. + + </para> + + </section> + + </section> + + <section> + <title>Using Time Stamps to Decide If a File Has Changed</title> + + <para> + + If you prefer, you can + configure &SCons; to use the modification time + of a file, not the file contents, + when deciding if a target needs to be rebuilt. + &SCons; gives you two ways to use time stamps + to decide if an input file has changed + since the last time a target has been built. + + </para> + + <para> + + The most familiar way to use time stamps + is the way &Make; does: + that is, have &SCons; decide + that a target must be rebuilt + if a source file's modification time is + <emphasis>newer</emphasis> + than the target file. + To do this, call the &Decider; + function as follows: + + </para> + + <scons_example name="newer"> + <file name="SConstruct" printme="1"> + Program('hello.c') + Decider('timestamp-newer') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + This makes &SCons; act like &Make; + when a file's modification time is updated + (using the &touch; command, for example): + + </para> + + <scons_output example="newer" os="posix"> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command>touch hello.c</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + + <para> + + And, in fact, because this behavior is the same + as the behavior of &Make;, + you can also use the string <literal>'make'</literal> + as a synonym for <literal>'timestamp-newer'</literal> + when calling the &Decider; function: + + </para> + + <sconstruct> + Program('hello.c') + Decider('make') + </sconstruct> + + <para> + + One drawback to using times stamps exactly like &Make; + is that if an input file's modification time suddenly + becomes <emphasis>older</emphasis> than a target file, + the target file will not be rebuilt. + This can happen if an old copy of a source file is restored + from a backup archive, for example. + The contents of the restored file will likely be different + than they were the last time a dependent target was built, + but the target won't be rebuilt + because the modification time of the source file + is not newer than the target. + + </para> + + <para> + + Because &SCons; actually stores information + about the source files' time stamps whenever a target is built, + it can handle this situation by checking for + an exact match of the source file time stamp, + instead of just whether or not the source file + is newer than the target file. + To do this, specify the argument + <literal>'timestamp-match'</literal> + when calling the &Decider; function: + + </para> + + <scons_example name="match"> + <file name="SConstruct" printme="1"> + Program('hello.c') + Decider('timestamp-match') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + When configured this way, + &SCons; will rebuild a target whenever + a source file's modification time has changed. + So if we use the <literal>touch -t</literal> + option to change the modification time of + &hello_c; to an old date (January 1, 1989), + &SCons; will still rebuild the target file: + + </para> + + <scons_output example="match" os="posix"> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command>touch -t 198901010000 hello.c</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + + <para> + + In general, the only reason to prefer + <literal>timestamp-newer</literal> + instead of + <literal>timestamp-match</literal>, + would be if you have some specific reason + to require this &Make;-like behavior of + not rebuilding a target when an otherwise-modified + source file is older. + + </para> + + </section> + + <section> + <title>Deciding If a File Has Changed Using Both MD Signatures and Time Stamps</title> + + <para> + + As a performance enhancement, + &SCons; provides a way to use + MD5 checksums of file contents + but to read those contents + only when the file's timestamp has changed. + To do this, call the &Decider; + function with <literal>'MD5-timestamp'</literal> + argument as follows: + + </para> + + <scons_example name="MD5-timestamp"> + <file name="SConstruct" printme="1"> + Program('hello.c') + Decider('MD5-timestamp') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + So configured, &SCons will still behave like + it does when using <literal>Decider('MD5')</literal>: + + </para> + + <!-- + + We want to generate the output as follows, + but our "surrogate" system for generating the + output seems to get this wrong. + Just in-line the output for now. + + <scons_output example="MD5-timestamp" os="posix"> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command>touch hello.c</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command output=" [CHANGE THE CONTENTS OF hello.c]">edit hello.c</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>touch hello.c</userinput> + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + % <userinput>edit hello.c</userinput> + [CHANGE THE CONTENTS OF hello.c] + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + <para> + + However, the second call to &SCons; in the above output, + when the build is up-to-date, + will have been performed by simply looking at the + modification time of the &hello_c; file, + not by opening it and performing + an MD5 checksum calcuation on its contents. + This can significantly speed up many up-to-date builds. + + </para> + + <para> + + The only drawback to using + <literal>Decider('MD5-timestamp')</literal> + is that &SCons; will <emphasis>not</emphasis> + rebuild a target file if a source file was modified + within one second of the last time &SCons; built the file. + While most developers are programming, + this isn't a problem in practice, + since it's unlikely that someone will have built + and then thought quickly enough to make a substantive + change to a source file within one second. + Certain build scripts or + continuous integration tools may, however, + rely on the ability to apply changes to files + automatically and then rebuild as quickly as possible, + in which case use of + <literal>Decider('MD5-timestamp')</literal> + may not be appropriate. + + </para> + + </section> + + <section> + <title>Writing Your Own Custom &Decider; Function</title> + + <para> + + The different string values that we've passed to + the &Decider; function are essentially used by &SCons; + to pick one of several specific internal functions + that implement various ways of deciding if a dependency + (usually a source file) + has changed since a target file has been built. + As it turns out, + you can also supply your own function + to decide if a dependency has changed. + + </para> + + <para> + + For example, suppose we have an input file + that contains a lot of data, + in some specific regular format, + that is used to rebuild a lot of different target files, + but each target file really only depends on + one particular section of the input file. + We'd like to have each target file depend on + only its section of the input file. + However, since the input file may contain a lot of data, + we want to open the input file only if its timestamp has changed. + This could done with a custom + &Decider; function that might look something like this: + + </para> + + <scons_example name="function"> + <file name="SConstruct" printme="1"> + Program('hello.c') + def decide_if_changed(dependency, target, prev_ni): + if self.get_timestamp() != prev_ni.timestamp: + dep = str(dependency) + tgt = str(target) + if specific_part_of_file_has_changed(dep, tgt): + return True + return False + Decider(decide_if_changed) + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + Note that in the function definition, + the <varname>dependency</varname> + (input file) is the first argument, + and then the ⌖. + Both of these are passed to the functions as + SCons &Node; objects, + which we convert to strings using the Python + <function>str()</function>. + + </para> + + <para> + + The third argument, <varname>prev_ni</varname>, + is an object that holds the + signature or timestamp information + that was recorded about the dependency + the last time the target was built. + A <varname>prev_ni</varname> object can hold + different information, + depending on the type of thing that the + <varname>dependency</varname> argument represents. + For normal files, + the <varname>prev_ni</varname> object + has the following attributes: + + </para> + + <variablelist> + + <varlistentry> + <term>.csig</term> + + <listitem> + <para> + The <emphasis>content signature</emphasis>, + or MD5 checksum, of the contents of the + <varname>dependency</varname> + file the list time the ⌖ was built. + </para> + </listitem> + + </varlistentry> + + <varlistentry> + <term>.size</term> + + <listitem> + <para> + The size in bytes of the <varname>dependency</varname> + file the list time the target was built. + </para> + </listitem> + + </varlistentry> + + <varlistentry> + <term>.timestamp</term> + + <listitem> + <para> + The modification time of the <varname>dependency</varname> + file the list time the ⌖ was built. + </para> + </listitem> + + </varlistentry> + + </variablelist> + + <para> + + Note that ignoring some of the arguments + in your custom &Decider; function + is a perfectly normal thing to do, + if they don't impact the way you want to + decide if the dependency file has changed. + + </para> + + </section> + + <section> + <title>Mixing Different Ways of Deciding If a File Has Changed</title> + + <para> + + The previous examples have all demonstrated calling + the global &Decider; function + to configure all dependency decisions that &SCons; makes. + Sometimes, however, you want to be able to configure + different decision-making for different targets. + When that's necessary, you can use the + <function>env.Decider</function> + method to affect only the configuration + decisions for targets built with a + specific construction environment. + + </para> + + <para> + + For example, if we arbitrarily want to build + one program using MD5 checkums + and another using file modification times + from the same source + we might configure it this way: + + </para> + + <scons_example name="mixing"> + <file name="SConstruct" printme="1"> + env1 = Environment(CPPPATH = ['.']) + env2 = env1.Clone() + env2.Decider('timestamp-match') + env1.Program('prog-MD5', 'program1.c') + env2.Program('prog-timestamp', 'program2.c') + </file> + <file name="program1.c"> + #include "inc.h" + int main() { printf("Hello, world!\n"); } + </file> + <file name="program2.c"> + #include "inc.h" + int main() { printf("Hello, world!\n"); } + </file> + <file name="inc.h"> + #define INC 1 + </file> + </scons_example> + + <para> + + If both of the programs include the same + <filename>inc.h</filename> file, + then updating the modification time of + <filename>inc.h</filename> + (using the &touch; command) + will cause only <filename>prog-timestamp</filename> + to be rebuilt: + + </para> + + <scons_output example="mixing" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>touch inc.h</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + </section> + + <section> + <title>Older Functions for Deciding When an Input File Has Changed</title> + + <para> + + &SCons; still supports two functions that used to be the + primary methods for configuring the + decision about whether or not an input file has changed. + Although they're not officially deprecated yet, + their use is discouraged, + mainly because they rely on a somewhat + confusing distinction between how + source files and target files are handled. + These functions are documented here mainly in case you + encounter them in existing &SConscript; files. + + </para> + + <section> + <title>The &SourceSignatures; Function</title> + + <para> + + The &SourceSignatures; function is fairly straightforward, + and supports two different argument values + to configure whether source file changes should be decided + using MD5 signatures: + + </para> + + <sconstruct> + Program('hello.c') + SourceSignatures('MD5') + </sconstruct> + + <para> + + Or using time stamps: + + </para> + + <sconstruct> + Program('hello.c') + SourceSignatures('timestamp') + </sconstruct> + + <para> + + These are roughly equivalent to specifying + <function>Decider('MD5')</function> + or + <function>Decider('timestamp-match')</function>, + respectively, + although it only affects how SCons makes + decisions about dependencies on + <emphasis>source</emphasis> files--that is, + files that are not built from any other files. + + </para> + + </section> + + <section> + <title>The &TargetSignatures; Function</title> + + <para> + + The &TargetSignatures; function + specifies how &SCons; decides + when a target file has changed + <emphasis>when it is used as a + dependency of (input to) another target</emphasis>--that is, + the &TargetSignatures; function configures + how the signatures of "intermediate" target files + are used when deciding if a "downstream" target file + must be rebuilt. + <footnote><para> + This easily-overlooked distinction between + how &SCons; decides if the target itself must be rebuilt + and how the target is then used to decide if a different + target must be rebuilt is one of the confusing + things that has led to the &TargetSignatures; + and &SourceSignatures; functions being + replaced by the simpler &Decider; function. + </para></footnote> + + </para> + + <para> + + The &TargetSignatures; function supports the same + <literal>'MD5'</literal> and <literal>'timestamp'</literal> + argument values that are supported by the &SourceSignatures;, + with the same meanings, but applied to target files. + That is, in the example: + + </para> + + <sconstruct> + Program('hello.c') + TargetSignatures('MD5') + </sconstruct> + + <para> + + The MD5 checksum of the &hello_o; target file + will be used to decide if it has changed since the last + time the "downstream" &hello; target file was built. + And in the example: + + </para> + + <sconstruct> + Program('hello.c') + TargetSignatures('timestamp') + </sconstruct> + + <para> + + The modification time of the &hello_o; target file + will be used to decide if it has changed since the last + time the "downstream" &hello; target file was built. + + </para> + + <para> + + The &TargetSignatures; function supports + two additional argument values: + <literal>'source'</literal> and <literal>'build'</literal>. + The <literal>'source'</literal> argument + specifies that decisions involving + whether target files have changed + since a previous build + should use the same behavior + for the decisions configured for source files + (using the &SourceSignatures; function). + So in the example: + + </para> + + <sconstruct> + Program('hello.c') + TargetSignatures('source') + SourceSignatures('timestamp') + </sconstruct> + + <para> + + All files, both targets and sources, + will use modification times + when deciding if an input file + has changed since the last + time a target was built. + + </para> + + <para> + + Lastly, the <literal>'build'</literal> argument + specifies that &SCons; should examine + the build status of a target file + and always rebuild a "downstream" target + if the target file was itself rebuilt, + without re-examining the contents or timestamp + of the newly-built target file. + If the target file was not rebuilt during + this &scons; invocation, + then the target file will be examined + the same way as configured by + the &SourceSignature; call + to decide if it has changed. + + </para> + + <para> + + This mimics the behavior of + <literal>build signatures</literal> + in earlier versions of &SCons;. + A &buildsignature; re-combined + signatures of all the input files + that went into making the target file, + so that the target file itself + did not need to have its contents read + to compute an MD5 signature. + This can improve performance for some configurations, + but is generally not as effective as using + <literal>Decider('MD5-timestamp')</literal>. + + </para> + + </section> + + </section> + + <section> + <title>Implicit Dependencies: The &cv-CPPPATH; Construction Variable</title> + + <para> + + Now suppose that our "Hello, World!" program + actually has an <literal>#include</literal> line + to include the &hello_h; file in the compilation: + + </para> + + <scons_example name="include"> + <file name="SConstruct"> + Program('hello.c', CPPPATH = '.') + </file> + <file name="hello.c" printme="1"> + #include <hello.h> + int + main() + { + printf("Hello, %s!\n", string); + } + </file> + <file name="hello.h"> + #define string "world" + </file> + </scons_example> + + <para> + + And, for completeness, the &hello_h; file looks like this: + + </para> + + <scons_example_file example="include" name="hello.h"> + </scons_example_file> + + <para> + + In this case, we want &SCons; to recognize that, + if the contents of the &hello_h; file change, + the &hello; program must be recompiled. + To do this, we need to modify the + &SConstruct; file like so: + + </para> + + <scons_example_file example="include" name="SConstruct"> + </scons_example_file> + + <para> + + The &cv-link-CPPPATH; value + tells &SCons; to look in the current directory + (<literal>'.'</literal>) + for any files included by C source files + (<filename>.c</filename> or <filename>.h</filename> files). + With this assignment in the &SConstruct; file: + + </para> + + <scons_output example="include" os="posix"> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command output=" [CHANGE THE CONTENTS OF hello.h]">edit hello.h</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + + <para> + + First, notice that &SCons; + added the <literal>-I.</literal> argument + from the &cv-CPPPATH; variable + so that the compilation would find the + &hello_h; file in the local directory. + + </para> + + <para> + + Second, realize that &SCons; knows that the &hello; + program must be rebuilt + because it scans the contents of + the &hello_c; file + for the <literal>#include</literal> 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> + + Like the &cv-link-LIBPATH; variable, + the &cv-CPPPATH; variable + may be a list of directories, + or a string separated by + the system-specific path separation character + (':' on POSIX/Linux, ';' on Windows). + Either way, &SCons; creates the + right command-line options + so that the following example: + + </para> + + <scons_example name="ex5"> + <file name="SConstruct" printme="1"> + Program('hello.c', CPPPATH = ['include', '/home/project/inc']) + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + Will look like this on POSIX or Linux: + + </para> + + <scons_output example="ex5" os="posix"> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + + <para> + + And like this on Windows: + + </para> + + <scons_output example="ex5" os="win32"> + <scons_output_command>scons -Q hello.exe</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Caching Implicit Dependencies</title> + + <para> + + Scanning each file for <literal>#include</literal> lines + does take some extra processing time. + When you're doing a full build of a large system, + the scanning time is usually a very small percentage + of the overall time spent on the build. + You're most likely to notice the scanning time, + however, when you <emphasis>rebuild</emphasis> + all or part of a large system: + &SCons; will likely take some extra time to "think about" + what must be built before it issues the + first build command + (or decides that everything is up to date + and nothing must be rebuilt). + + <!-- + 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> + + <para> + + In practice, having &SCons; scan files saves time + relative to the amount of potential time + lost to tracking down subtle problems + introduced by incorrect dependencies. + Nevertheless, the "waiting time" + while &SCons; scans files can annoy + individual developers waiting for their builds to finish. + Consequently, &SCons; lets you cache + the implicit dependencies + that its scanners find, + for use by later builds. + You can do this by specifying the + &implicit-cache; option on the command line: + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q --implicit-cache hello</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + + <para> + + If you don't want to specify &implicit-cache; + on the command line each time, + you can make it the default behavior for your build + by setting the &implicit_cache; option + in an &SConscript; file: + + </para> + + <sconstruct> + SetOption('implicit_cache', 1) + </sconstruct> + + <para> + + &SCons; does not cache implicit dependencies like this by default + because the &implicit-cache; causes &SCons; to simply use the implicit + dependencies stored during the last run, without any checking + for whether or not those dependencies are still correct. + Specifically, this means &implicit-cache; instructs &SCons; + to <emphasis>not</emphasis> rebuild "correctly" in the + following cases: + + + </para> + + <itemizedlist> + + <listitem> + <para> + + When &implicit-cache; is used, &SCons; will ignore any changes that + may have been made to search paths + (like &cv-CPPPATH; or &cv-LIBPATH;,). + This can lead to &SCons; not rebuilding a file if a change to + &cv-CPPPATH; would normally cause a different, same-named file from + a different directory to be used. + + </para> + </listitem> + + <listitem> + <para> + + When &implicit-cache; is used, &SCons; will not detect if a + same-named file has been added to a directory that is earlier in + the search path than the directory in which the file was found + last time. + + </para> + </listitem> + + </itemizedlist> + + <section> + <title>The &implicit-deps-changed; Option</title> + + <para> + + When using cached implicit dependencies, + sometimes you want to "start fresh" + and have &SCons; re-scan the files + for which it previously cached the dependencies. + For example, + if you have recently installed a new version of + external code that you use for compilation, + the external header files will have changed + and the previously-cached implicit dependencies + will be out of date. + You can update them by + running &SCons; with the &implicit-deps-changed; option: + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q --implicit-deps-changed hello</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + + <para> + + In this case, &SCons; will re-scan all of the implicit dependencies + and cache updated copies of the information. + + </para> + + </section> + + <section> + <title>The &implicit-deps-unchanged; Option</title> + + <para> + + By default when caching dependencies, + &SCons; notices when a file has been modified + and re-scans the file for any updated + implicit dependency information. + Sometimes, however, you may want + to force &SCons; to use the cached implicit dependencies, + even if the source files changed. + This can speed up a build for example, + when you have changed your source files + but know that you haven't changed + any <literal>#include</literal> lines. + In this case, + you can use the &implicit-deps-unchanged; option: + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q --implicit-deps-unchanged hello</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + + <para> + + In this case, + &SCons; will assume that the cached implicit + dependencies are correct and + will not bother to re-scan changed files. + For typical builds after small, + incremental changes to source files, + the savings may not be very big, + but sometimes every bit of + improved performance counts. + + </para> + + </section> + + <!-- + + <section> + <title>XXX max drift</title> + + XXX SetOption('max_drift') + + </section> + + --> + + </section> + + <section> + <title>Explicit Dependencies: the &Depends; Function</title> + + <para> + + Sometimes a file depends on another file + that is not detected by an &SCons; scanner. + For this situation, + &SCons; allows you to specific explicitly that one file + depends on another file, + and must be rebuilt whenever that file changes. + This is specified using the &Depends; method: + + </para> + + <programlisting> + hello = Program('hello.c') + Depends(hello, 'other_file') + </programlisting> + + <!-- XXX mention that you can use arrays for target and source? --> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + % <userinput>edit other_file</userinput> + [CHANGE THE CONTENTS OF other_file] + % <userinput>scons -Q hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + </screen> + + <para> + + Note that the dependency + (the second argument to &Depends;) + may also be a list of Node objects + (for example, as returned by a call to a Builder): + + </para> + + <programlisting> + hello = Program('hello.c') + goodbye = Program('goodbye.c') + Depends(hello, goodbye) + </programlisting> + + <para> + + in which case the dependency or dependencies + will be built before the target(s): + + </para> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -c goodbye.c -o goodbye.o + cc -o goodbye goodbye.o + cc -c hello.c -o hello.o + cc -o hello hello.o + </screen> + + </section> + + <section> + <title>Dependencies From External Files: the &ParseDepends; + Function</title> + + <para> + + &SCons; has built-in scanners for a number of languages. Sometimes + these scanners fail to extract certain implicit dependencies due + to limitations of the scanner implementation. + + </para> + + <para> + + The following example illustrates a case where the built-in C + scanner is unable to extract the implicit dependency on a header + file. + + </para> + + <scons_example name="macroinc"> + <file name="hello.c" printme="1"> + #define FOO_HEADER <foo.h> + #include FOO_HEADER + + int main() { + return FOO; + } + </file> + <file name="SConstruct"> + Program('hello', 'hello.c', CPPPATH='.') + </file> + <file name="foo.h"> + #define FOO 42 + </file> + </scons_example> + + <scons_output example="macroinc" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command output=" [CHANGE CONTENTS OF foo.h]" + >edit foo.h</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Apparently, the scanner does not know about the header dependency. + Being not a full-fledged C preprocessor, the scanner does not + expand the macro. + + </para> + + <para> + + In these cases, you may also use the compiler to extract the + implicit dependencies. &ParseDepends; can parse the contents of + the compiler output in the style of &Make;, and explicitly + establish all of the listed dependencies. + + </para> + + <para> + + The following example uses &ParseDepends; to process a compiler + generated dependency file which is generated as a side effect + during compilation of the object file: + + </para> + + <!-- XXX The ParseDepends example below fakes proper working by a + priori specification of the dependency file. The produced hello.d + file is not found (or used) for unknown reasons. --> + + <scons_example name="parsedep"> + <file name="hello.c"> + #define FOO_HEADER <foo.h> + #include FOO_HEADER + + int main() { + return FOO; + } + </file> + <file name="SConstruct" printme="1"> + obj = Object('hello.c', CCFLAGS='-MD -MF hello.d', CPPPATH='.') + SideEffect('hello.d', obj) + ParseDepends('hello.d') + Program('hello', obj) + </file> + <file name="foo.h"> + #define FOO 42 + </file> + <file name="hello.d"> + hello.o: hello.c foo.h + </file> + </scons_example> + + <scons_output example="parsedep" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command output=" [CHANGE CONTENTS OF foo.h]" + >edit foo.h</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Parsing dependencies from a compiler-generated + <filename>.d</filename> file has a chicken-and-egg problem, that + causes unnecessary rebuilds: + + </para> + + <scons_example name="parsedeprebuild"> + <file name="hello.c"> + #define FOO_HEADER <foo.h> + #include FOO_HEADER + + int main() { + return FOO; + } + </file> + <file name="SConstruct"> + obj = Object('hello.c', CCFLAGS='-MD -MF hello.d', CPPPATH='.') + SideEffect('hello.d', obj) + ParseDepends('hello.d') + Program('hello', obj) + </file> + <file name="foo.h"> + #define FOO 42 + </file> + </scons_example> + + <!-- + <scons_output example="parsedeprebuild" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + --> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c -MD -MF hello.d -I. hello.c + cc -o hello hello.o + % <userinput>scons -Q --debug=explain</userinput> + scons: rebuilding `hello.o' because `foo.h' is a new dependency + cc -o hello.o -c -MD -MF hello.d -I. hello.c + % <userinput>scons -Q</userinput> + scons: `.' is up to date. + </screen> + + <para> + + In the first pass, the dependency file is generated while the + object file is compiled. At that time, &SCons; does not know about + the dependency on <filename>foo.h</filename>. In the second pass, + the object file is regenerated because <filename>foo.h</filename> + is detected as a new dependency. + + </para> + + <para> + + &ParseDepends; immediately reads the specified file at invocation + time and just returns if the file does not exist. A dependency + file generated during the build process is not automatically + parsed again. Hence, the compiler-extracted dependencies are not + stored in the signature database during the same build pass. This + limitation of &ParseDepends; leads to unnecessary recompilations. + Therefore, &ParseDepends; should only be used if scanners are not + available for the employed language or not powerful enough for the + specific task. + + </para> + + </section> + + <section> + <title>Ignoring Dependencies: the &Ignore; Function</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> + + <scons_example name="ignore"> + <file name="SConstruct" printme="1"> + hello = Program('hello.c') + Ignore(hello, 'hello.h') + </file> + <file name="hello.c"> + #include "hello.h" + int main() { printf("Hello, %s!\n", string); } + </file> + <file name="hello.h"> + #define string "world" + </file> + </scons_example> + + <!-- XXX mention that you can use lists for target and source? --> + + <!-- + <scons_output example="ignore"> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command output=" [CHANGE THE CONTENTS OF hello.h]">edit hello.h</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + XXX THIS EXAMPLE SHOULD BE UP-TO-DATE! XXX + </scons_output> + --> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -c -o hello.o hello.c + cc -o hello hello.o + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + % <userinput>edit hello.h</userinput> + [CHANGE THE CONTENTS OF hello.h] + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + </screen> + + <para> + + Now, the above example is a little contrived, + because it's hard to imagine a real-world situation + where you wouldn't want 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> + hello = Program('hello.c', CPPPATH=['/usr/include']) + Ignore(hello, '/usr/include/stdio.h') + </programlisting> + + <para> + &Ignore; can also be used to prevent a generated file from being built + by default. This is due to the fact that directories depend on + their contents. So to ignore a generated file from the default build, + you specify that the directory should ignore the generated file. + Note that the file will still be built if the user specifically + requests the target on scons command line, or if the file is + a dependency of another file which is requested and/or is built + by default. + </para> + + <scons_example name="ignore_explicit"> + <file name="SConstruct" printme="1"> + hello_obj=Object('hello.c') + hello = Program(hello_obj) + Ignore('.',[hello,hello_obj]) + </file> + <file name="hello.c"> + #include "stdio.h" + int main() { printf("Hello!\n"); } + </file> + </scons_example> + + <scons_output example="ignore_explicit" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + </section> + + <section> + <title>Order-Only Dependencies: the &Requires; Function</title> + + <para> + + Occasionally, + it may be useful to specify that a certain + file or directory must, if necessary, + be built or created before some other target is built, + but that changes to that file or directory + do <emphasis>not</emphasis> + require that the target itself be rebuilt. + Such a relationship is called an + <emphasis>order-only dependency</emphasis> + because it only affects the order in which + things must be built--the dependency before the target--but + it is not a strict dependency relationship + because the target should not + change in response to changes in the dependent file. + + </para> + + <para> + + For example, suppose that you want to create a file + every time you run a build + that identifies the time the build was performed, + the version number, etc., + and which is included in every program that you build. + The version file's contents will change every build. + If you specify a normal dependency relationship, + then every program that depends on + that file would be rebuilt every time you ran &SCons;. + For example, we could use some Python code in + a &SConstruct; file to create a new <filename>version.c</filename> file + with a string containing the current date every time + we run &SCons;, + and then link a program with the resulting object file + by listing <filename>version.c</filename> in the sources: + + </para> + + <scons_example name="no-Requires"> + <file name="SConstruct" printme="1"> + import time + + version_c_text = """ + char *date = "%s"; + """ % time.ctime(time.time()) + open('version.c', 'w').write(version_c_text) + + hello = Program(['hello.c', 'version.c']) + </file> + <file name="hello.c"> + extern char *date; + int main() { printf("Hello, %s! I was built: %s\n", date); } + </file> + </scons_example> + + <para> + + If we list <filename>version.c</filename> as an actual source file, + though, then <filename>version.o</filename> + will get rebuilt every time we run &SCons; + (because the &SConstruct; file itself changes + the contents of <filename>version.c</filename>) + and the <filename>hello</filename> executable + will get re-linked every time + (because the <filename>version.o</filename> file changes): + + </para> + + <!-- + + <scons_output example="no-Requires"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + gcc -o hello.o -c hello.c + gcc -o version.o -c version.c + gcc -o hello hello.o version.o + % <userinput>scons -Q</userinput> + gcc -o version.o -c version.c + gcc -o hello hello.o version.o + % <userinput>scons -Q</userinput> + gcc -o version.o -c version.c + gcc -o hello hello.o version.o + </screen> + + <para> + + One solution is to use the &Requires; function + to specify that the <filename>version.o</filename> + must be rebuilt before it is used by the link step, + but that changes to <filename>version.o</filename> + should not actually cause the <filename>hello</filename> + executable to be re-linked: + + </para> + + <scons_example name="Requires"> + <file name="SConstruct" printme="1"> + import time + + version_c_text = """ + char *date = "%s"; + """ % time.ctime(time.time()) + open('version.c', 'w').write(version_c_text) + + version_obj = Object('version.c') + + hello = Program('hello.c', + LINKFLAGS = str(version_obj[0])) + + Requires(hello, version_obj) + </file> + <file name="hello.c"> + extern char *date; + int main() { printf("Hello, %s! I was built: %s\n", date); } + </file> + </scons_example> + + <para> + + Notice that because we can no longer list <filename>version.c</filename> + as one of the sources for the <filename>hello</filename> program, + we have to find some other way to get it into the link command line. + For this example, we're cheating a bit and stuffing the + object file name (extracted from <literal>version_obj</literal> + list returned by the &b-Object; call) + into the &cv-link-LINKFLAGS; variable, + because &cv-LINKFLAGS; is already included + in the &cv-link-LINKCOM; command line. + + </para> + + <para> + + With these changes, + we get the desired behavior of + re-building the <filename>version.o</filename> file, + and therefore re-linking the <filename>hello</filename> executable, + only when the <filename>hello.c</filename> has changed: + + </para> + + <scons_output example="Requires"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command output=" [CHANGE THE CONTENTS OF hello.c]">edit hello.c</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>The &AlwaysBuild; Function</title> + + <para> + + How &SCons; handles dependencies can also be affected + by the &AlwaysBuild; method. + When a file is passed to the &AlwaysBuild; method, + like so: + + </para> + + <scons_example name="AlwaysBuild"> + <file name="SConstruct" printme="1"> + hello = Program('hello.c') + AlwaysBuild(hello) + </file> + <file name="hello.c"> + int main() { printf("Hello, %s!\n", string); } + </file> + </scons_example> + + <para> + + Then the specified target file (&hello; in our example) + will always be considered out-of-date and + rebuilt whenever that target file is evaluated + while walking the dependency graph: + + </para> + + <scons_output example="AlwaysBuild"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + The &AlwaysBuild; function has a somewhat misleading name, + because it does not actually mean the target file will + be rebuilt every single time &SCons; is invoked. + Instead, it means that the target will, in fact, + be rebuilt whenever the target file is encountered + while evaluating the targets specified on + the command line (and their dependencies). + So specifying some other target on the command line, + a target that does <emphasis>not</emphasis> + itself depend on the &AlwaysBuild; target, + will still be rebuilt only if it's out-of-date + with respect to its dependencies: + + </para> + + <scons_output example="AlwaysBuild"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q hello.o</scons_output_command> + </scons_output> + + <!-- + + XXX AlwaysBuild() and Alias Nodes + + XXX AlwaysBuild() and Dir Nodes + + XXX AlwaysBuild() with no sources + + --> + + </section> + + <!-- + + <section> + <title>The &Salt; Method</title> + + <para> + + XXX Salt() (are we going to implement this ?) + + original Cons classic POD documentation: + +=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> + + </section> + + --> diff --git a/doc/user/depends.xml b/doc/user/depends.xml new file mode 100644 index 0000000..b72f41f --- /dev/null +++ b/doc/user/depends.xml @@ -0,0 +1,1776 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + So far we've seen how &SCons; handles one-time builds. + But one of the main functions of a build tool like &SCons; + is to rebuild only what is necessary + when source files change--or, put another way, + &SCons; should <emphasis>not</emphasis> + waste time rebuilding things that don't need to be rebuilt. + You can see this at work simply by re-invoking &SCons; + after building our simple &hello; example: + + </para> + + + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q</userinput> + scons: `.' is up to date. + </screen> + + <para> + + The second time it is executed, + &SCons; realizes 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> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + </screen> + + <para> + + Note that &SCons; reports <literal>"...is up to date"</literal> + only for target files named explicitly on the command line, + to avoid cluttering the output. + + </para> + + <section> + <title>Deciding When an Input File Has Changed: the &Decider; Function</title> + + <para> + + Another aspect of avoiding unnecessary rebuilds + is the fundamental build tool behavior + of <emphasis>rebuilding</emphasis> + things when an input file changes, + so that the built software is up to date. + By default, + &SCons; keeps track of this through an + MD5 &signature;, or checksum, of the contents of each file, + although you can easily configure + &SCons; to use the + modification times (or time stamps) + instead. + You can even specify your own Python function + for deciding if an input file has changed. + + </para> + + <section> + <title>Using MD5 Signatures to Decide if a File Has Changed</title> + + <para> + + By default, + &SCons; keeps track of whether a file has changed + based on an MD5 checksum of the file's contents, + not the file's modification time. + This means that you may be surprised by the + default &SCons; behavior if you are used to the + &Make; convention of forcing + a rebuild by updating the file's modification time + (using the &touch; command, for example): + + </para> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>touch hello.c</userinput> + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + </screen> + + <para> + + Even though the file's modification time has changed, + &SCons; realizes that the contents of the + &hello_c; file have <emphasis>not</emphasis> changed, + and therefore that the &hello; program + need not be rebuilt. + This avoids unnecessary rebuilds when, + for example, someone rewrites the + contents of a file without making a change. + But if the contents of the file really do change, + then &SCons; detects the change + and rebuilds the program as required: + + </para> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>edit hello.c</userinput> + [CHANGE THE CONTENTS OF hello.c] + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + <para> + + Note that you can, if you wish, + specify this default behavior + (MD5 signatures) explicitly + using the &Decider; function as follows: + + </para> + + <programlisting> + Program('hello.c') + Decider('MD5') + </programlisting> + + <para> + + You can also use the string <literal>'content'</literal> + as a synonym for <literal>'MD5'</literal> + when calling the &Decider; function. + + </para> + + <section> + <title>Ramifications of Using MD5 Signatures</title> + + <para> + + Using MD5 signatures to decide if an input file has changed + has one surprising benefit: + if a source file has been changed + in such a way that the contents of the + rebuilt target file(s) + will be exactly the same as the last time + the file was built, + then any "downstream" target files + that depend on the rebuilt-but-not-changed target + file actually need not be rebuilt. + + </para> + + <para> + + So if, for example, + a user were to only change a comment in a &hello_c; file, + then the rebuilt &hello_o; file + would be exactly the same as the one previously built + (assuming the compiler doesn't put any build-specific + information in the object file). + &SCons; would then realize that it would not + need to rebuild the &hello; program as follows: + + </para> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>edit hello.c</userinput> + [CHANGE A COMMENT IN hello.c] + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + scons: `hello' is up to date. + </screen> + + <para> + + In essence, &SCons; + "short-circuits" any dependent builds + when it realizes that a target file + has been rebuilt to exactly the same file as the last build. + This does take some extra processing time + to read the contents of the target (&hello_o;) file, + but often saves time when the rebuild that was avoided + would have been time-consuming and expensive. + + </para> + + </section> + + </section> + + <section> + <title>Using Time Stamps to Decide If a File Has Changed</title> + + <para> + + If you prefer, you can + configure &SCons; to use the modification time + of a file, not the file contents, + when deciding if a target needs to be rebuilt. + &SCons; gives you two ways to use time stamps + to decide if an input file has changed + since the last time a target has been built. + + </para> + + <para> + + The most familiar way to use time stamps + is the way &Make; does: + that is, have &SCons; decide + that a target must be rebuilt + if a source file's modification time is + <emphasis>newer</emphasis> + than the target file. + To do this, call the &Decider; + function as follows: + + </para> + + <programlisting> + Program('hello.c') + Decider('timestamp-newer') + </programlisting> + + <para> + + This makes &SCons; act like &Make; + when a file's modification time is updated + (using the &touch; command, for example): + + </para> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>touch hello.c</userinput> + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + <para> + + And, in fact, because this behavior is the same + as the behavior of &Make;, + you can also use the string <literal>'make'</literal> + as a synonym for <literal>'timestamp-newer'</literal> + when calling the &Decider; function: + + </para> + + <programlisting> + Program('hello.c') + Decider('make') + </programlisting> + + <para> + + One drawback to using times stamps exactly like &Make; + is that if an input file's modification time suddenly + becomes <emphasis>older</emphasis> than a target file, + the target file will not be rebuilt. + This can happen if an old copy of a source file is restored + from a backup archive, for example. + The contents of the restored file will likely be different + than they were the last time a dependent target was built, + but the target won't be rebuilt + because the modification time of the source file + is not newer than the target. + + </para> + + <para> + + Because &SCons; actually stores information + about the source files' time stamps whenever a target is built, + it can handle this situation by checking for + an exact match of the source file time stamp, + instead of just whether or not the source file + is newer than the target file. + To do this, specify the argument + <literal>'timestamp-match'</literal> + when calling the &Decider; function: + + </para> + + <programlisting> + Program('hello.c') + Decider('timestamp-match') + </programlisting> + + <para> + + When configured this way, + &SCons; will rebuild a target whenever + a source file's modification time has changed. + So if we use the <literal>touch -t</literal> + option to change the modification time of + &hello_c; to an old date (January 1, 1989), + &SCons; will still rebuild the target file: + + </para> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>touch -t 198901010000 hello.c</userinput> + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + <para> + + In general, the only reason to prefer + <literal>timestamp-newer</literal> + instead of + <literal>timestamp-match</literal>, + would be if you have some specific reason + to require this &Make;-like behavior of + not rebuilding a target when an otherwise-modified + source file is older. + + </para> + + </section> + + <section> + <title>Deciding If a File Has Changed Using Both MD Signatures and Time Stamps</title> + + <para> + + As a performance enhancement, + &SCons; provides a way to use + MD5 checksums of file contents + but to read those contents + only when the file's timestamp has changed. + To do this, call the &Decider; + function with <literal>'MD5-timestamp'</literal> + argument as follows: + + </para> + + <programlisting> + Program('hello.c') + Decider('MD5-timestamp') + </programlisting> + + <para> + + So configured, &SCons; will still behave like + it does when using <literal>Decider('MD5')</literal>: + + </para> + + <!-- + + We want to generate the output as follows, + but our "surrogate" system for generating the + output seems to get this wrong. + Just in-line the output for now. + + <scons_output example="MD5-timestamp" os="posix"> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command>touch hello.c</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command output=" [CHANGE THE CONTENTS OF hello.c]">edit hello.c</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>touch hello.c</userinput> + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + % <userinput>edit hello.c</userinput> + [CHANGE THE CONTENTS OF hello.c] + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + <para> + + However, the second call to &SCons; in the above output, + when the build is up-to-date, + will have been performed by simply looking at the + modification time of the &hello_c; file, + not by opening it and performing + an MD5 checksum calcuation on its contents. + This can significantly speed up many up-to-date builds. + + </para> + + <para> + + The only drawback to using + <literal>Decider('MD5-timestamp')</literal> + is that &SCons; will <emphasis>not</emphasis> + rebuild a target file if a source file was modified + within one second of the last time &SCons; built the file. + While most developers are programming, + this isn't a problem in practice, + since it's unlikely that someone will have built + and then thought quickly enough to make a substantive + change to a source file within one second. + Certain build scripts or + continuous integration tools may, however, + rely on the ability to apply changes to files + automatically and then rebuild as quickly as possible, + in which case use of + <literal>Decider('MD5-timestamp')</literal> + may not be appropriate. + + </para> + + </section> + + <section> + <title>Writing Your Own Custom &Decider; Function</title> + + <para> + + The different string values that we've passed to + the &Decider; function are essentially used by &SCons; + to pick one of several specific internal functions + that implement various ways of deciding if a dependency + (usually a source file) + has changed since a target file has been built. + As it turns out, + you can also supply your own function + to decide if a dependency has changed. + + </para> + + <para> + + For example, suppose we have an input file + that contains a lot of data, + in some specific regular format, + that is used to rebuild a lot of different target files, + but each target file really only depends on + one particular section of the input file. + We'd like to have each target file depend on + only its section of the input file. + However, since the input file may contain a lot of data, + we want to open the input file only if its timestamp has changed. + This could done with a custom + &Decider; function that might look something like this: + + </para> + + <programlisting> + Program('hello.c') + def decide_if_changed(dependency, target, prev_ni): + if self.get_timestamp() != prev_ni.timestamp: + dep = str(dependency) + tgt = str(target) + if specific_part_of_file_has_changed(dep, tgt): + return True + return False + Decider(decide_if_changed) + </programlisting> + + <para> + + Note that in the function definition, + the <varname>dependency</varname> + (input file) is the first argument, + and then the ⌖. + Both of these are passed to the functions as + SCons &Node; objects, + which we convert to strings using the Python + <function>str()</function>. + + </para> + + <para> + + The third argument, <varname>prev_ni</varname>, + is an object that holds the + signature or timestamp information + that was recorded about the dependency + the last time the target was built. + A <varname>prev_ni</varname> object can hold + different information, + depending on the type of thing that the + <varname>dependency</varname> argument represents. + For normal files, + the <varname>prev_ni</varname> object + has the following attributes: + + </para> + + <variablelist> + + <varlistentry> + <term>.csig</term> + + <listitem> + <para> + The <emphasis>content signature</emphasis>, + or MD5 checksum, of the contents of the + <varname>dependency</varname> + file the list time the ⌖ was built. + </para> + </listitem> + + </varlistentry> + + <varlistentry> + <term>.size</term> + + <listitem> + <para> + The size in bytes of the <varname>dependency</varname> + file the list time the target was built. + </para> + </listitem> + + </varlistentry> + + <varlistentry> + <term>.timestamp</term> + + <listitem> + <para> + The modification time of the <varname>dependency</varname> + file the list time the ⌖ was built. + </para> + </listitem> + + </varlistentry> + + </variablelist> + + <para> + + Note that ignoring some of the arguments + in your custom &Decider; function + is a perfectly normal thing to do, + if they don't impact the way you want to + decide if the dependency file has changed. + + </para> + + </section> + + <section> + <title>Mixing Different Ways of Deciding If a File Has Changed</title> + + <para> + + The previous examples have all demonstrated calling + the global &Decider; function + to configure all dependency decisions that &SCons; makes. + Sometimes, however, you want to be able to configure + different decision-making for different targets. + When that's necessary, you can use the + <function>env.Decider</function> + method to affect only the configuration + decisions for targets built with a + specific construction environment. + + </para> + + <para> + + For example, if we arbitrarily want to build + one program using MD5 checkums + and another using file modification times + from the same source + we might configure it this way: + + </para> + + <programlisting> + env1 = Environment(CPPPATH = ['.']) + env2 = env1.Clone() + env2.Decider('timestamp-match') + env1.Program('prog-MD5', 'program1.c') + env2.Program('prog-timestamp', 'program2.c') + </programlisting> + + <para> + + If both of the programs include the same + <filename>inc.h</filename> file, + then updating the modification time of + <filename>inc.h</filename> + (using the &touch; command) + will cause only <filename>prog-timestamp</filename> + to be rebuilt: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o program1.o -c -I. program1.c + cc -o prog-MD5 program1.o + cc -o program2.o -c -I. program2.c + cc -o prog-timestamp program2.o + % <userinput>touch inc.h</userinput> + % <userinput>scons -Q</userinput> + cc -o program2.o -c -I. program2.c + cc -o prog-timestamp program2.o + </screen> + + </section> + + </section> + + <section> + <title>Older Functions for Deciding When an Input File Has Changed</title> + + <para> + + &SCons; still supports two functions that used to be the + primary methods for configuring the + decision about whether or not an input file has changed. + Although they're not officially deprecated yet, + their use is discouraged, + mainly because they rely on a somewhat + confusing distinction between how + source files and target files are handled. + These functions are documented here mainly in case you + encounter them in existing &SConscript; files. + + </para> + + <section> + <title>The &SourceSignatures; Function</title> + + <para> + + The &SourceSignatures; function is fairly straightforward, + and supports two different argument values + to configure whether source file changes should be decided + using MD5 signatures: + + </para> + + <programlisting> + Program('hello.c') + SourceSignatures('MD5') + </programlisting> + + <para> + + Or using time stamps: + + </para> + + <programlisting> + Program('hello.c') + SourceSignatures('timestamp') + </programlisting> + + <para> + + These are roughly equivalent to specifying + <function>Decider('MD5')</function> + or + <function>Decider('timestamp-match')</function>, + respectively, + although it only affects how SCons makes + decisions about dependencies on + <emphasis>source</emphasis> files--that is, + files that are not built from any other files. + + </para> + + </section> + + <section> + <title>The &TargetSignatures; Function</title> + + <para> + + The &TargetSignatures; function + specifies how &SCons; decides + when a target file has changed + <emphasis>when it is used as a + dependency of (input to) another target</emphasis>--that is, + the &TargetSignatures; function configures + how the signatures of "intermediate" target files + are used when deciding if a "downstream" target file + must be rebuilt. + <footnote><para> + This easily-overlooked distinction between + how &SCons; decides if the target itself must be rebuilt + and how the target is then used to decide if a different + target must be rebuilt is one of the confusing + things that has led to the &TargetSignatures; + and &SourceSignatures; functions being + replaced by the simpler &Decider; function. + </para></footnote> + + </para> + + <para> + + The &TargetSignatures; function supports the same + <literal>'MD5'</literal> and <literal>'timestamp'</literal> + argument values that are supported by the &SourceSignatures;, + with the same meanings, but applied to target files. + That is, in the example: + + </para> + + <programlisting> + Program('hello.c') + TargetSignatures('MD5') + </programlisting> + + <para> + + The MD5 checksum of the &hello_o; target file + will be used to decide if it has changed since the last + time the "downstream" &hello; target file was built. + And in the example: + + </para> + + <programlisting> + Program('hello.c') + TargetSignatures('timestamp') + </programlisting> + + <para> + + The modification time of the &hello_o; target file + will be used to decide if it has changed since the last + time the "downstream" &hello; target file was built. + + </para> + + <para> + + The &TargetSignatures; function supports + two additional argument values: + <literal>'source'</literal> and <literal>'build'</literal>. + The <literal>'source'</literal> argument + specifies that decisions involving + whether target files have changed + since a previous build + should use the same behavior + for the decisions configured for source files + (using the &SourceSignatures; function). + So in the example: + + </para> + + <programlisting> + Program('hello.c') + TargetSignatures('source') + SourceSignatures('timestamp') + </programlisting> + + <para> + + All files, both targets and sources, + will use modification times + when deciding if an input file + has changed since the last + time a target was built. + + </para> + + <para> + + Lastly, the <literal>'build'</literal> argument + specifies that &SCons; should examine + the build status of a target file + and always rebuild a "downstream" target + if the target file was itself rebuilt, + without re-examining the contents or timestamp + of the newly-built target file. + If the target file was not rebuilt during + this &scons; invocation, + then the target file will be examined + the same way as configured by + the &SourceSignature; call + to decide if it has changed. + + </para> + + <para> + + This mimics the behavior of + <literal>build signatures</literal> + in earlier versions of &SCons;. + A &buildsignature; re-combined + signatures of all the input files + that went into making the target file, + so that the target file itself + did not need to have its contents read + to compute an MD5 signature. + This can improve performance for some configurations, + but is generally not as effective as using + <literal>Decider('MD5-timestamp')</literal>. + + </para> + + </section> + + </section> + + <section> + <title>Implicit Dependencies: The &cv-CPPPATH; Construction Variable</title> + + <para> + + Now suppose that our "Hello, World!" program + actually has an <literal>#include</literal> line + to include the &hello_h; file in the compilation: + + </para> + + <programlisting> + #include <hello.h> + int + main() + { + printf("Hello, %s!\n", string); + } + </programlisting> + + <para> + + And, for completeness, the &hello_h; file looks like this: + + </para> + + + <programlisting> + #define string "world" + </programlisting> + + <para> + + In this case, we want &SCons; to recognize that, + if the contents of the &hello_h; file change, + the &hello; program must be recompiled. + To do this, we need to modify the + &SConstruct; file like so: + + </para> + + + <programlisting> + Program('hello.c', CPPPATH = '.') + </programlisting> + + <para> + + The &cv-link-CPPPATH; value + tells &SCons; to look in the current directory + (<literal>'.'</literal>) + for any files included by C source files + (<filename>.c</filename> or <filename>.h</filename> files). + With this assignment in the &SConstruct; file: + + </para> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c -I. hello.c + cc -o hello hello.o + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + % <userinput>edit hello.h</userinput> + [CHANGE THE CONTENTS OF hello.h] + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c -I. hello.c + cc -o hello hello.o + </screen> + + <para> + + First, notice that &SCons; + added the <literal>-I.</literal> argument + from the &cv-CPPPATH; variable + so that the compilation would find the + &hello_h; file in the local directory. + + </para> + + <para> + + Second, realize that &SCons; knows that the &hello; + program must be rebuilt + because it scans the contents of + the &hello_c; file + for the <literal>#include</literal> 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> + + Like the &cv-link-LIBPATH; variable, + the &cv-CPPPATH; variable + may be a list of directories, + or a string separated by + the system-specific path separation character + (':' on POSIX/Linux, ';' on Windows). + Either way, &SCons; creates the + right command-line options + so that the following example: + + </para> + + <programlisting> + Program('hello.c', CPPPATH = ['include', '/home/project/inc']) + </programlisting> + + <para> + + Will look like this on POSIX or Linux: + + </para> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c -Iinclude -I/home/project/inc hello.c + cc -o hello hello.o + </screen> + + <para> + + And like this on Windows: + + </para> + + <screen> + C:\><userinput>scons -Q hello.exe</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + cl /Fohello.obj /c hello.c /nologo /Iinclude /I\home\project\inc + link /nologo /OUT:hello.exe hello.obj + </screen> + + </section> + + <section> + <title>Caching Implicit Dependencies</title> + + <para> + + Scanning each file for <literal>#include</literal> lines + does take some extra processing time. + When you're doing a full build of a large system, + the scanning time is usually a very small percentage + of the overall time spent on the build. + You're most likely to notice the scanning time, + however, when you <emphasis>rebuild</emphasis> + all or part of a large system: + &SCons; will likely take some extra time to "think about" + what must be built before it issues the + first build command + (or decides that everything is up to date + and nothing must be rebuilt). + + <!-- + 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> + + <para> + + In practice, having &SCons; scan files saves time + relative to the amount of potential time + lost to tracking down subtle problems + introduced by incorrect dependencies. + Nevertheless, the "waiting time" + while &SCons; scans files can annoy + individual developers waiting for their builds to finish. + Consequently, &SCons; lets you cache + the implicit dependencies + that its scanners find, + for use by later builds. + You can do this by specifying the + &implicit-cache; option on the command line: + + </para> + + <screen> + % <userinput>scons -Q --implicit-cache hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + </screen> + + <para> + + If you don't want to specify &implicit-cache; + on the command line each time, + you can make it the default behavior for your build + by setting the &implicit_cache; option + in an &SConscript; file: + + </para> + + <programlisting> + SetOption('implicit_cache', 1) + </programlisting> + + <para> + + &SCons; does not cache implicit dependencies like this by default + because the &implicit-cache; causes &SCons; to simply use the implicit + dependencies stored during the last run, without any checking + for whether or not those dependencies are still correct. + Specifically, this means &implicit-cache; instructs &SCons; + to <emphasis>not</emphasis> rebuild "correctly" in the + following cases: + + + </para> + + <itemizedlist> + + <listitem> + <para> + + When &implicit-cache; is used, &SCons; will ignore any changes that + may have been made to search paths + (like &cv-CPPPATH; or &cv-LIBPATH;,). + This can lead to &SCons; not rebuilding a file if a change to + &cv-CPPPATH; would normally cause a different, same-named file from + a different directory to be used. + + </para> + </listitem> + + <listitem> + <para> + + When &implicit-cache; is used, &SCons; will not detect if a + same-named file has been added to a directory that is earlier in + the search path than the directory in which the file was found + last time. + + </para> + </listitem> + + </itemizedlist> + + <section> + <title>The &implicit-deps-changed; Option</title> + + <para> + + When using cached implicit dependencies, + sometimes you want to "start fresh" + and have &SCons; re-scan the files + for which it previously cached the dependencies. + For example, + if you have recently installed a new version of + external code that you use for compilation, + the external header files will have changed + and the previously-cached implicit dependencies + will be out of date. + You can update them by + running &SCons; with the &implicit-deps-changed; option: + + </para> + + <screen> + % <userinput>scons -Q --implicit-deps-changed hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + </screen> + + <para> + + In this case, &SCons; will re-scan all of the implicit dependencies + and cache updated copies of the information. + + </para> + + </section> + + <section> + <title>The &implicit-deps-unchanged; Option</title> + + <para> + + By default when caching dependencies, + &SCons; notices when a file has been modified + and re-scans the file for any updated + implicit dependency information. + Sometimes, however, you may want + to force &SCons; to use the cached implicit dependencies, + even if the source files changed. + This can speed up a build for example, + when you have changed your source files + but know that you haven't changed + any <literal>#include</literal> lines. + In this case, + you can use the &implicit-deps-unchanged; option: + + </para> + + <screen> + % <userinput>scons -Q --implicit-deps-unchanged hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + </screen> + + <para> + + In this case, + &SCons; will assume that the cached implicit + dependencies are correct and + will not bother to re-scan changed files. + For typical builds after small, + incremental changes to source files, + the savings may not be very big, + but sometimes every bit of + improved performance counts. + + </para> + + </section> + + <!-- + + <section> + <title>XXX max drift</title> + + XXX SetOption('max_drift') + + </section> + + --> + + </section> + + <section> + <title>Explicit Dependencies: the &Depends; Function</title> + + <para> + + Sometimes a file depends on another file + that is not detected by an &SCons; scanner. + For this situation, + &SCons; allows you to specific explicitly that one file + depends on another file, + and must be rebuilt whenever that file changes. + This is specified using the &Depends; method: + + </para> + + <programlisting> + hello = Program('hello.c') + Depends(hello, 'other_file') + </programlisting> + + <!-- XXX mention that you can use arrays for target and source? --> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + % <userinput>edit other_file</userinput> + [CHANGE THE CONTENTS OF other_file] + % <userinput>scons -Q hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + </screen> + + <para> + + Note that the dependency + (the second argument to &Depends;) + may also be a list of Node objects + (for example, as returned by a call to a Builder): + + </para> + + <programlisting> + hello = Program('hello.c') + goodbye = Program('goodbye.c') + Depends(hello, goodbye) + </programlisting> + + <para> + + in which case the dependency or dependencies + will be built before the target(s): + + </para> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -c goodbye.c -o goodbye.o + cc -o goodbye goodbye.o + cc -c hello.c -o hello.o + cc -o hello hello.o + </screen> + + </section> + + <section> + <title>Dependencies From External Files: the &ParseDepends; + Function</title> + + <para> + + &SCons; has built-in scanners for a number of languages. Sometimes + these scanners fail to extract certain implicit dependencies due + to limitations of the scanner implementation. + + </para> + + <para> + + The following example illustrates a case where the built-in C + scanner is unable to extract the implicit dependency on a header + file. + + </para> + + <programlisting> + #define FOO_HEADER <foo.h> + #include FOO_HEADER + + int main() { + return FOO; + } + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c -I. hello.c + cc -o hello hello.o + % <userinput>edit foo.h</userinput> + [CHANGE CONTENTS OF foo.h] + % <userinput>scons -Q</userinput> + scons: `.' is up to date. + </screen> + + <para> + + Apparently, the scanner does not know about the header dependency. + Being not a full-fledged C preprocessor, the scanner does not + expand the macro. + + </para> + + <para> + + In these cases, you may also use the compiler to extract the + implicit dependencies. &ParseDepends; can parse the contents of + the compiler output in the style of &Make;, and explicitly + establish all of the listed dependencies. + + </para> + + <para> + + The following example uses &ParseDepends; to process a compiler + generated dependency file which is generated as a side effect + during compilation of the object file: + + </para> + + <!-- XXX The ParseDepends example below fakes proper working by a + priori specification of the dependency file. The produced hello.d + file is not found (or used) for unknown reasons. --> + + <programlisting> + obj = Object('hello.c', CCFLAGS='-MD -MF hello.d', CPPPATH='.') + SideEffect('hello.d', obj) + ParseDepends('hello.d') + Program('hello', obj) + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c -MD -MF hello.d -I. hello.c + cc -o hello hello.o + % <userinput>edit foo.h</userinput> + [CHANGE CONTENTS OF foo.h] + % <userinput>scons -Q</userinput> + cc -o hello.o -c -MD -MF hello.d -I. hello.c + </screen> + + <para> + + Parsing dependencies from a compiler-generated + <filename>.d</filename> file has a chicken-and-egg problem, that + causes unnecessary rebuilds: + + </para> + + + + <!-- + <scons_output example="parsedeprebuild" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + --> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c -MD -MF hello.d -I. hello.c + cc -o hello hello.o + % <userinput>scons -Q --debug=explain</userinput> + scons: rebuilding `hello.o' because `foo.h' is a new dependency + cc -o hello.o -c -MD -MF hello.d -I. hello.c + % <userinput>scons -Q</userinput> + scons: `.' is up to date. + </screen> + + <para> + + In the first pass, the dependency file is generated while the + object file is compiled. At that time, &SCons; does not know about + the dependency on <filename>foo.h</filename>. In the second pass, + the object file is regenerated because <filename>foo.h</filename> + is detected as a new dependency. + + </para> + + <para> + + &ParseDepends; immediately reads the specified file at invocation + time and just returns if the file does not exist. A dependency + file generated during the build process is not automatically + parsed again. Hence, the compiler-extracted dependencies are not + stored in the signature database during the same build pass. This + limitation of &ParseDepends; leads to unnecessary recompilations. + Therefore, &ParseDepends; should only be used if scanners are not + available for the employed language or not powerful enough for the + specific task. + + </para> + + </section> + + <section> + <title>Ignoring Dependencies: the &Ignore; Function</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> + hello = Program('hello.c') + Ignore(hello, 'hello.h') + </programlisting> + + <!-- XXX mention that you can use lists for target and source? --> + + <!-- + <scons_output example="ignore"> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + <scons_output_command output=" [CHANGE THE CONTENTS OF hello.h]">edit hello.h</scons_output_command> + <scons_output_command>scons -Q hello</scons_output_command> + XXX THIS EXAMPLE SHOULD BE UP-TO-DATE! XXX + </scons_output> + --> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -c -o hello.o hello.c + cc -o hello hello.o + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + % <userinput>edit hello.h</userinput> + [CHANGE THE CONTENTS OF hello.h] + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + </screen> + + <para> + + Now, the above example is a little contrived, + because it's hard to imagine a real-world situation + where you wouldn't want 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> + hello = Program('hello.c', CPPPATH=['/usr/include']) + Ignore(hello, '/usr/include/stdio.h') + </programlisting> + + <para> + &Ignore; can also be used to prevent a generated file from being built + by default. This is due to the fact that directories depend on + their contents. So to ignore a generated file from the default build, + you specify that the directory should ignore the generated file. + Note that the file will still be built if the user specifically + requests the target on scons command line, or if the file is + a dependency of another file which is requested and/or is built + by default. + </para> + + <programlisting> + hello_obj=Object('hello.c') + hello = Program(hello_obj) + Ignore('.',[hello,hello_obj]) + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + scons: `.' is up to date. + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + </screen> + </section> + + <section> + <title>Order-Only Dependencies: the &Requires; Function</title> + + <para> + + Occasionally, + it may be useful to specify that a certain + file or directory must, if necessary, + be built or created before some other target is built, + but that changes to that file or directory + do <emphasis>not</emphasis> + require that the target itself be rebuilt. + Such a relationship is called an + <emphasis>order-only dependency</emphasis> + because it only affects the order in which + things must be built--the dependency before the target--but + it is not a strict dependency relationship + because the target should not + change in response to changes in the dependent file. + + </para> + + <para> + + For example, suppose that you want to create a file + every time you run a build + that identifies the time the build was performed, + the version number, etc., + and which is included in every program that you build. + The version file's contents will change every build. + If you specify a normal dependency relationship, + then every program that depends on + that file would be rebuilt every time you ran &SCons;. + For example, we could use some Python code in + a &SConstruct; file to create a new <filename>version.c</filename> file + with a string containing the current date every time + we run &SCons;, + and then link a program with the resulting object file + by listing <filename>version.c</filename> in the sources: + + </para> + + <programlisting> + import time + + version_c_text = """ + char *date = "%s"; + """ % time.ctime(time.time()) + open('version.c', 'w').write(version_c_text) + + hello = Program(['hello.c', 'version.c']) + </programlisting> + + <para> + + If we list <filename>version.c</filename> as an actual source file, + though, then <filename>version.o</filename> + will get rebuilt every time we run &SCons; + (because the &SConstruct; file itself changes + the contents of <filename>version.c</filename>) + and the <filename>hello</filename> executable + will get re-linked every time + (because the <filename>version.o</filename> file changes): + + </para> + + <!-- + + <scons_output example="no-Requires"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + gcc -o hello.o -c hello.c + gcc -o version.o -c version.c + gcc -o hello hello.o version.o + % <userinput>scons -Q</userinput> + gcc -o version.o -c version.c + gcc -o hello hello.o version.o + % <userinput>scons -Q</userinput> + gcc -o version.o -c version.c + gcc -o hello hello.o version.o + </screen> + + <para> + + One solution is to use the &Requires; function + to specify that the <filename>version.o</filename> + must be rebuilt before it is used by the link step, + but that changes to <filename>version.o</filename> + should not actually cause the <filename>hello</filename> + executable to be re-linked: + + </para> + + <programlisting> + import time + + version_c_text = """ + char *date = "%s"; + """ % time.ctime(time.time()) + open('version.c', 'w').write(version_c_text) + + version_obj = Object('version.c') + + hello = Program('hello.c', + LINKFLAGS = str(version_obj[0])) + + Requires(hello, version_obj) + </programlisting> + + <para> + + Notice that because we can no longer list <filename>version.c</filename> + as one of the sources for the <filename>hello</filename> program, + we have to find some other way to get it into the link command line. + For this example, we're cheating a bit and stuffing the + object file name (extracted from <literal>version_obj</literal> + list returned by the &b-Object; call) + into the &cv-link-LINKFLAGS; variable, + because &cv-LINKFLAGS; is already included + in the &cv-link-LINKCOM; command line. + + </para> + + <para> + + With these changes, + we get the desired behavior of + re-building the <filename>version.o</filename> file, + and therefore re-linking the <filename>hello</filename> executable, + only when the <filename>hello.c</filename> has changed: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o version.o -c version.c + cc -o hello.o -c hello.c + cc -o hello version.o hello.o + % <userinput>scons -Q</userinput> + scons: `.' is up to date. + % <userinput>edit hello.c</userinput> + [CHANGE THE CONTENTS OF hello.c] + % <userinput>scons -Q</userinput> + cc -o version.o -c version.c + cc -o hello.o -c hello.c + cc -o hello version.o hello.o + % <userinput>scons -Q</userinput> + scons: `.' is up to date. + </screen> + + </section> + + <section> + <title>The &AlwaysBuild; Function</title> + + <para> + + How &SCons; handles dependencies can also be affected + by the &AlwaysBuild; method. + When a file is passed to the &AlwaysBuild; method, + like so: + + </para> + + <programlisting> + hello = Program('hello.c') + AlwaysBuild(hello) + </programlisting> + + <para> + + Then the specified target file (&hello; in our example) + will always be considered out-of-date and + rebuilt whenever that target file is evaluated + while walking the dependency graph: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q</userinput> + cc -o hello hello.o + </screen> + + <para> + + The &AlwaysBuild; function has a somewhat misleading name, + because it does not actually mean the target file will + be rebuilt every single time &SCons; is invoked. + Instead, it means that the target will, in fact, + be rebuilt whenever the target file is encountered + while evaluating the targets specified on + the command line (and their dependencies). + So specifying some other target on the command line, + a target that does <emphasis>not</emphasis> + itself depend on the &AlwaysBuild; target, + will still be rebuilt only if it's out-of-date + with respect to its dependencies: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q hello.o</userinput> + scons: `hello.o' is up to date. + </screen> + + <!-- + + XXX AlwaysBuild() and Alias Nodes + + XXX AlwaysBuild() and Dir Nodes + + XXX AlwaysBuild() with no sources + + --> + + </section> + + <!-- + + <section> + <title>The &Salt; Method</title> + + <para> + + XXX Salt() (are we going to implement this ?) + + original Cons classic POD documentation: + +=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> + + </section> + + --> diff --git a/doc/user/environments.in b/doc/user/environments.in new file mode 100644 index 0000000..124aaaa --- /dev/null +++ b/doc/user/environments.in @@ -0,0 +1,1678 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 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 Windows 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 + +XXX DESCRIBE THE Literal() FUNCTION, TOO XXX + +=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. + +--> + + <para> + + An <literal>environment</literal> + is a collection of values that + can affect how a program executes. + &SCons; distinguishes between three + different types of environments + that can affect the behavior of &SCons; itself + (subject to the configuration in the &SConscript; files), + as well as the compilers and other tools it executes: + + </para> + + <variablelist> + + <varlistentry> + <term>External Environment</term> + + <listitem> + <para> + + The <literal>external environment</literal> + is the set of variables in the user's environment + at the time the user runs &SCons. + These variables are available within the &SConscript; files + through the Python <literal>os.environ</literal> dictionary. + See <xref linkend="sect-external-environments"></xref>, below. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>&ConsEnv;</term> + + <listitem> + <para> + + A &consenv; + is a distinct object creating within + a &SConscript; file and + and which contains values that + affect how &SCons; decides + what action to use to build a target, + and even to define which targets + should be built from which sources. + One of the most powerful features of &SCons; + is the ability to create multiple &consenvs;, + including the ability to clone a new, customized + &consenv; from an existing &consenv;. + See <xref linkend="sect-construction-environments"></xref>, below. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Execution Environment</term> + + <listitem> + <para> + + An <literal>execution environment</literal> + is the values that &SCons; sets + when executing an external + command (such as a compiler or linker) + to build one or more targets. + Note that this is not the same as + the <literal>external environment</literal> + (see above). + See <xref linkend="sect-execution-environments"></xref>, below. + + </para> + </listitem> + </varlistentry> + + </variablelist> + + <para> + + Unlike &Make;, &SCons; does not automatically + copy or import values between different environments + (with the exception of explicit clones of &consenvs, + which inherit values from their parent). + This is a deliberate design choice + to make sure that builds are, + by default, repeatable regardless of + the values in the user's external environment. + This avoids a whole class of problems with builds + where a developer's local build works + because a custom variable setting + causes a different compiler or build option to be used, + but the checked-in change breaks the official build + because it uses different environment variable settings. + + </para> + + <para> + + Note that the &SConscript; writer can + easily arrange for variables to be + copied or imported between environments, + and this is often very useful + (or even downright necessary) + to make it easy for developers + to customize the build in appropriate ways. + The point is <emphasis>not</emphasis> + that copying variables between different environments + is evil and must always be avoided. + Instead, it should be up to the + implementer of the build system + to make conscious choices + about how and when to import + a variable from one environment to another, + making informed decisions about + striking the right balance + between making the build + repeatable on the one hand + and convenient to use on the other. + + </para> + + <section id="sect-external-environments"> + <title>Using Values From the External Environment</title> + + <para> + + The <literal>external environment</literal> + variable settings that + the user has in force + when executing &SCons; + are available through the normal Python + <envar>os.environ</envar> + dictionary. + This means that you must add an + <literal>import os</literal> statement + to any &SConscript; file + in which you want to use + values from the user's external environment. + + </para> + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + import os + </file> + <file name="foo.c"> + int main() { } + </file> + </scons_example> + + <para> + + More usefully, you can use the + <envar>os.environ</envar> + dictionary in your &SConscript; + files to initialize &consenvs; + with values from the user's external environment. + See the next section, + <xref linkend="sect-construction-environments"></xref>, + for information on how to do this. + + </para> + + </section> + + <section id="sect-construction-environments"> + <title>Construction Environments</title> + + <para> + + It is rare that all of the software in a large, + complicated system needs to be built the same way. + For example, different source files may need different options + enabled on the command line, + or different executable programs need to be linked + with different libraries. + &SCons; accommodates these different build + requirements by allowing you to create and + configure multiple &consenvs; + that control how the software is built. + A &consenv; is an object + that has a number of associated + &consvars;, each with a name and a value. + (A construction environment also has an attached + set of &Builder; methods, + about which we'll learn more later.) + + </para> + + <section> + <title>Creating a &ConsEnv;: the &Environment; Function</title> + + <para> + + A &consenv; is created by the &Environment; method: + + </para> + + <sconstruct> + env = Environment() + </sconstruct> + + <para> + + By default, &SCons; initializes every + new construction environment + with a set of &consvars; + based on the tools that it finds on your system, + plus the default set of builder methods + necessary for using those tools. + The construction variables + are initialized with values describing + the C compiler, + the Fortran compiler, + the linker, + etc., + as well as the command lines to invoke them. + + </para> + + <para> + + When you initialize a construction environment + you can set the values of the + environment's &consvars; + to control how a program is built. + For example: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + env = Environment(CC = 'gcc', + CCFLAGS = '-O2') + + env.Program('foo.c') + </file> + <file name="foo.c"> + int main() { } + </file> + </scons_example> + + <para> + + The construction environment in this example + is still initialized with the same default + construction variable values, + except that the user has explicitly specified use of the + GNU C compiler &gcc;, + and further specifies that the <literal>-O2</literal> + (optimization level two) + flag should be used when compiling the object file. + In other words, the explicit initializations of + &cv-link-CC; and &cv-link-CCFLAGS; + override the default values in the newly-created + construction environment. + So a run from this example would look like: + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Fetching Values From a &ConsEnv;</title> + + <para> + + You can fetch individual construction variables + using the normal syntax + for accessing individual named items in a Python dictionary: + + </para> + + <scons_example name="ex6"> + <file name="SConstruct" printme="1"> + env = Environment() + print "CC is:", env['CC'] + </file> + </scons_example> + + <para> + + This example &SConstruct; file doesn't build anything, + but because it's actually a Python script, + it will print the value of &cv-link-CC; for us: + + </para> + + <scons_output example="ex6"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + A construction environment, however, + is actually an object with associated methods, etc. + If you want to have direct access to only the + dictionary of construction variables, + you can fetch this using the &Dictionary; method: + + </para> + + <scons_example name="ex6b"> + <file name="SConstruct" printme="1"> + env = Environment(FOO = 'foo', BAR = 'bar') + dict = env.Dictionary() + for key in ['OBJSUFFIX', 'LIBSUFFIX', 'PROGSUFFIX']: + print "key = %s, value = %s" % (key, dict[key]) + </file> + </scons_Example> + + <para> + + This &SConstruct; file + will print the specified dictionary items for us on POSIX + systems as follows: + + </para> + + <scons_output example="ex6b" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + And on Windows: + + </para> + + <scons_output example="ex6b" os="win32"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + If you want to loop and print the values of + all of the construction variables in a construction environment, + the Python code to do that in sorted order might look something like: + + </para> + + <sconstruct> + env = Environment() + dict = env.Dictionary() + keys = dict.keys() + keys.sort() + for key in keys: + print "construction variable = '%s', value = '%s'" % (key, dict[key]) + </sconstruct> + + </section> + + <section> + <title>Expanding Values From a &ConsEnv;: the &subst; Method</title> + + <para> + + Another way to get information from + a construction environment. + is to use the &subst; method + on a string containing <literal>$</literal> expansions + of construction variable names. + As a simple example, + the example from the previous + section that used + <literal>env['CC']</literal> + to fetch the value of &cv-link-CC; + could also be written as: + + </para> + + <sconstruct> + env = Environment() + print "CC is:", env.subst('$CC') + </sconstruct> + + <para> + + One advantage of using + &subst; to expand strings is + that construction variables + in the result get re-expanded until + there are no expansions left in the string. + So a simple fetch of a value like + &cv-link-CCCOM;: + + </para> + + <sconstruct> + env = Environment(CCFLAGS = '-DFOO') + print "CCCOM is:", env['CCCOM'] + </sconstruct> + + <para> + + Will print the unexpanded value of &cv-CCCOM;, + showing us the construction + variables that still need to be expanded: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + CCCOM is: $CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES + scons: `.' is up to date. + </screen> + + <para> + + Calling the &subst; method on <varname>$CCOM</varname>, + however: + + </para> + + <sconstruct> + env = Environment(CCFLAGS = '-DFOO') + print "CCCOM is:", env.subst('$CCCOM') + </sconstruct> + + <para> + + Will recursively expand all of + the construction variables prefixed + with <literal>$</literal> (dollar signs), + showing us the final output: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + CCCOM is: gcc -DFOO -c -o + scons: `.' is up to date. + </screen> + + <para> + + Note that because we're not expanding this + in the context of building something + there are no target or source files + for &cv-link-TARGET; and &cv-link-SOURCES; to expand. + + </para> + + </section> + + <section> + <title>Controlling the Default &ConsEnv;: the &DefaultEnvironment; Function</title> + + <para> + + All of the &Builder; functions that we've introduced so far, + like &Program; and &Library;, + actually use a default &consenv; + that contains settings + for the various compilers + and other tools that + &SCons; configures by default, + or otherwise knows about + and has discovered on your system. + The goal of the default construction environment + is to make many configurations to "just work" + to build software using + readily available tools + with a minimum of configuration changes. + + </para> + + <para> + + You can, however, control the settings + in the default contstruction environment + by using the &DefaultEnvironment; function + to initialize various settings: + + </para> + + <sconstruct> + + DefaultEnvironment(CC = '/usr/local/bin/gcc') + + </sconstruct> + + <para> + + When configured as above, + all calls to the &Program; + or &Object; Builder + will build object files with the + <filename>/usr/local/bin/gcc</filename> + compiler. + + </para> + + <para> + + Note that the &DefaultEnvironment; function + returns the initialized + default construction environment object, + which can then be manipulated like any + other construction environment. + So the following + would be equivalent to the + previous example, + setting the &cv-CC; + variable to <filename>/usr/local/bin/gcc</filename> + but as a separate step after + the default construction environment has been initialized: + + </para> + + <sconstruct> + + env = DefaultEnvironment() + env['CC'] = '/usr/local/bin/gcc' + + </sconstruct> + + <para> + + One very common use of the &DefaultEnvironment; function + is to speed up &SCons; initialization. + As part of trying to make most default + configurations "just work," + &SCons; will actually + search the local system for installed + compilers and other utilities. + This search can take time, + especially on systems with + slow or networked file systems. + If you know which compiler(s) and/or + other utilities you want to configure, + you can control the search + that &SCons; performs + by specifying some specific + tool modules with which to + initialize the default construction environment: + + </para> + + <sconstruct> + + env = DefaultEnvironment(tools = ['gcc', 'gnulink'], + CC = '/usr/local/bin/gcc') + + </sconstruct> + + <para> + + So the above example would tell &SCons; + to explicitly configure the default environment + to use its normal GNU Compiler and GNU Linker settings + (without having to search for them, + or any other utilities for that matter), + and specifically to use the compiler found at + <filename>/usr/local/bin/gcc</filename>. + + </para> + + </section> + + <section> + <title>Multiple &ConsEnvs;</title> + + <para> + + The real advantage of construction environments + is that you can create as many different construction + environments as you need, + each tailored to a different way to build + some piece of software or other file. + If, for example, we need to build + one program with the <literal>-O2</literal> flag + and another with the <literal>-g</literal> (debug) flag, + we would do this like so: + + </para> + + <scons_example name="ex2"> + <file name="SConstruct" printme="1"> + opt = Environment(CCFLAGS = '-O2') + dbg = Environment(CCFLAGS = '-g') + + opt.Program('foo', 'foo.c') + + dbg.Program('bar', 'bar.c') + </file> + <file name="foo.c"> + int main() { } + </file> + <file name="bar.c"> + int main() { } + </file> + </scons_example> + + <scons_output example="ex2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + We can even use multiple construction environments to build + multiple versions of a single program. + If you do this by simply trying to use the + &b-link-Program; builder with both environments, though, + like this: + + </para> + + <scons_example name="ex3"> + <file name="SConstruct" printme="1"> + opt = Environment(CCFLAGS = '-O2') + dbg = Environment(CCFLAGS = '-g') + + opt.Program('foo', 'foo.c') + + dbg.Program('foo', 'foo.c') + </file> + <file name="foo.c"> + int main() { } + </file> + </scons_example> + + <para> + + Then &SCons; generates the following error: + + </para> + + <scons_output example="ex3"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + This is because the two &b-Program; calls have + each implicitly told &SCons; to generate an object file named + <filename>foo.o</filename>, + one with a &cv-link-CCFLAGS; value of + <literal>-O2</literal> + and one with a &cv-link-CCFLAGS; value of + <literal>-g</literal>. + &SCons; can't just decide that one of them + should take precedence over the other, + so it generates the error. + To avoid this problem, + we must explicitly specify + that each environment compile + <filename>foo.c</filename> + to a separately-named object file + using the &b-link-Object; builder, like so: + + </para> + + <scons_example name="ex4"> + <file name="SConstruct" printme="1"> + opt = Environment(CCFLAGS = '-O2') + dbg = Environment(CCFLAGS = '-g') + + o = opt.Object('foo-opt', 'foo.c') + opt.Program(o) + + d = dbg.Object('foo-dbg', 'foo.c') + dbg.Program(d) + </file> + <file name="foo.c"> + int main() { } + </file> + </scons_example> + + <para> + + Notice that each call to the &b-Object; builder + returns a value, + an internal &SCons; object that + represents the object file that will be built. + We then use that object + as input to the &b-Program; builder. + This avoids having to specify explicitly + the object file name in multiple places, + and makes for a compact, readable + &SConstruct; file. + Our &SCons; output then looks like: + + </para> + + <scons_output example="ex4"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Making Copies of &ConsEnvs;: the &Clone; Method</title> + + <para> + + Sometimes you want more than one construction environment + to share the same values for one or more variables. + Rather than always having to repeat all of the common + variables when you create each construction environment, + you can use the &Clone; method + to create a copy of a construction environment. + + </para> + + <para> + + Like the &Environment; call that creates a construction environment, + the &Clone; method takes &consvar; assignments, + which will override the values in the copied construction environment. + For example, suppose we want to use &gcc; + to create three versions of a program, + one optimized, one debug, and one with neither. + We could do this by creating a "base" construction environment + that sets &cv-link-CC; to &gcc;, + and then creating two copies, + one which sets &cv-link-CCFLAGS; for optimization + and the other which sets &cv-CCFLAGS; for debugging: + + </para> + + <scons_example name="ex5"> + <file name="SConstruct" printme="1"> + env = Environment(CC = 'gcc') + opt = env.Clone(CCFLAGS = '-O2') + dbg = env.Clone(CCFLAGS = '-g') + + env.Program('foo', 'foo.c') + + o = opt.Object('foo-opt', 'foo.c') + opt.Program(o) + + d = dbg.Object('foo-dbg', 'foo.c') + dbg.Program(d) + </file> + <file name="foo.c"> + int main() { } + </file> + </scons_example> + + <para> + + Then our output would look like: + + </para> + + <scons_output example="ex5"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Replacing Values: the &Replace; Method</title> + + <para> + + You can replace existing construction variable values + using the &Replace; method: + + </para> + + <scons_example name="Replace1"> + <file name="SConstruct" printme="1"> + env = Environment(CCFLAGS = '-DDEFINE1') + env.Replace(CCFLAGS = '-DDEFINE2') + env.Program('foo.c') + </file> + <file name="foo.c"> + int main() { } + </file> + </scons_example> + + <para> + + The replacing value + (<literal>-DDEFINE2</literal> in the above example) + completely replaces the value in the + construction environment: + + </para> + + <scons_output example="Replace1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + You can safely call &Replace; + for construction variables that + don't exist in the construction environment: + + </para> + + <scons_example name="Replace-nonexistent"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Replace(NEW_VARIABLE = 'xyzzy') + print "NEW_VARIABLE =", env['NEW_VARIABLE'] + </file> + </scons_example> + + <para> + + In this case, + the construction variable simply + gets added to the construction environment: + + </para> + + <scons_output example="Replace-nonexistent"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Because the variables + aren't expanded until the construction environment + is actually used to build the targets, + and because &SCons; function and method calls + are order-independent, + the last replacement "wins" + and is used to build all targets, + regardless of the order in which + the calls to Replace() are + interspersed with calls to + builder methods: + + </para> + + <scons_example name="Replace2"> + <file name="SConstruct" printme="1"> + env = Environment(CCFLAGS = '-DDEFINE1') + print "CCFLAGS =", env['CCFLAGS'] + env.Program('foo.c') + + env.Replace(CCFLAGS = '-DDEFINE2') + print "CCFLAGS =", env['CCFLAGS'] + env.Program('bar.c') + </file> + <file name="foo.c"> + int main() { } + </file> + <file name="bar.c"> + int main() { } + </file> + </scons_example> + + <para> + + The timing of when the replacement + actually occurs relative + to when the targets get built + becomes apparent + if we run &scons; without the <literal>-Q</literal> + option: + + </para> + + <scons_output example="Replace2"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + Because the replacement occurs while + the &SConscript; files are being read, + the &cv-link-CCFLAGS; + variable has already been set to + <literal>-DDEFINE2</literal> + by the time the &foo_o; target is built, + even though the call to the &Replace; + method does not occur until later in + the &SConscript; file. + + </para> + + </section> + + <section> + <title>Setting Values Only If They're Not Already Defined: the &SetDefault; Method</title> + + <para> + + Sometimes it's useful to be able to specify + that a construction variable should be + set to a value only if the construction environment + does not already have that variable defined + You can do this with the &SetDefault; method, + which behaves similarly to the <function>set_default</function> + method of Python dictionary objects: + + </para> + + <sconstruct> + env.SetDefault(SPECIAL_FLAG = '-extra-option') + </sconstruct> + + <para> + + This is especially useful + when writing your own <literal>Tool</literal> modules + to apply variables to construction environments. + <!-- + See <xref linkend="chap-tool-modules"></xref> + for more information about writing + Tool modules. + --> + + </para> + + </section> + + <section> + <title>Appending to the End of Values: the &Append; Method</title> + + <para> + + You can append a value to + an existing construction variable + using the &Append; method: + + </para> + + <scons_example name="ex8"> + <file name="SConstruct" printme="1"> + env = Environment(CCFLAGS = ['-DMY_VALUE']) + env.Append(CCFLAGS = ['-DLAST']) + env.Program('foo.c') + </file> + <file name="foo.c"> + int main() { } + </file> + </scons_example> + + <para> + + &SCons; then supplies both the <literal>-DMY_VALUE</literal> and + <literal>-DLAST</literal> flags when compiling the object file: + + </para> + + <scons_output example="ex8"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + If the construction variable doesn't already exist, + the &Append; method will create it: + + </para> + + <scons_example name="Append-nonexistent"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Append(NEW_VARIABLE = 'added') + print "NEW_VARIABLE =", env['NEW_VARIABLE'] + </file> + </scons_example> + + <para> + + Which yields: + + </para> + + <scons_output example="Append-nonexistent"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Note that the &Append; function tries to be "smart" + about how the new value is appended to the old value. + If both are strings, the previous and new strings + are simply concatenated. + Similarly, if both are lists, + the lists are concatenated. + If, however, one is a string and the other is a list, + the string is added as a new element to the list. + + </para> + + </section> + + <section> + <title>Appending Unique Values: the &AppendUnique; Method</title> + + <para> + + Some times it's useful to add a new value + only if the existing construction variable + doesn't already contain the value. + This can be done using the &AppendUnique; method: + + </para> + + <sconstruct> + env.AppendUnique(CCFLAGS=['-g']) + </sconstruct> + + <para> + + In the above example, + the <literal>-g</literal> would be added + only if the &cv-CCFLAGS; variable + does not already contain a <literal>-g</literal> value. + + </para> + + </section> + + <section> + <title>Appending to the Beginning of Values: the &Prepend; Method</title> + + <para> + + You can append a value to the beginning of + an existing construction variable + using the &Prepend; method: + + </para> + + <scons_example name="ex9"> + <file name="SConstruct" printme="1"> + env = Environment(CCFLAGS = ['-DMY_VALUE']) + env.Prepend(CCFLAGS = ['-DFIRST']) + env.Program('foo.c') + </file> + <file name="foo.c"> + int main() { } + </file> + </scons_example> + + <para> + + &SCons; then supplies both the <literal>-DFIRST</literal> and + <literal>-DMY_VALUE</literal> flags when compiling the object file: + + </para> + + <scons_output example="ex9"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + If the construction variable doesn't already exist, + the &Prepend; method will create it: + + </para> + + <scons_example name="Prepend-nonexistent"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Prepend(NEW_VARIABLE = 'added') + print "NEW_VARIABLE =", env['NEW_VARIABLE'] + </file> + </scons_example> + + <para> + + Which yields: + + </para> + + <scons_output example="Prepend-nonexistent"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Like the &Append; function, + the &Prepend; function tries to be "smart" + about how the new value is appended to the old value. + If both are strings, the previous and new strings + are simply concatenated. + Similarly, if both are lists, + the lists are concatenated. + If, however, one is a string and the other is a list, + the string is added as a new element to the list. + + </para> + + </section> + + <section> + <title>Prepending Unique Values: the &PrependUnique; Method</title> + + <para> + + Some times it's useful to add a new value + to the beginning of a construction variable + only if the existing value + doesn't already contain the to-be-added value. + This can be done using the &PrependUnique; method: + + </para> + + <sconstruct> + env.PrependUnique(CCFLAGS=['-g']) + </sconstruct> + + <para> + + In the above example, + the <literal>-g</literal> would be added + only if the &cv-CCFLAGS; variable + does not already contain a <literal>-g</literal> value. + + </para> + + </section> + + </section> + + <section id="sect-execution-environments"> + <title>Controlling the Execution Environment for Issued Commands</title> + + <para> + + When &SCons; builds a target file, + it does not execute the commands with + the same external environment + that you used to execute &SCons;. + Instead, it uses the dictionary + stored in the &cv-link-ENV; construction variable + as the external environment + for executing commands. + + </para> + + <para> + + The most important ramification of this behavior + is that the &PATH; environment variable, + which controls where the operating system + will look for commands and utilities, + is not the same as in the external environment + from which you called &SCons;. + This means that &SCons; will not, by default, + necessarily find all of the tools + that you can execute from the command line. + + </para> + + <para> + + The default value of the &PATH; environment variable + on a POSIX system + is <literal>/usr/local/bin:/bin:/usr/bin</literal>. + The default value of the &PATH; environment variable + on a Windows system comes from the Windows registry + value for the command interpreter. + If you want to execute any commands--compilers, linkers, etc.--that + are not in these default locations, + you need to set the &PATH; value + in the &cv-ENV; dictionary + in your construction environment. + + </para> + + <para> + + The simplest way to do this is to initialize explicitly + the value when you create the construction environment; + this is one way to do that: + + </para> + + <sconstruct> + path = ['/usr/local/bin', '/bin', '/usr/bin'] + env = Environment(ENV = {'PATH' : path}) + </sconstruct> + + <para> + + Assign a dictionary to the &cv-ENV; + construction variable in this way + completely resets the external environment + so that the only variable that will be + set when external commands are executed + will be the &PATH; value. + If you want to use the rest of + the values in &cv-ENV; and only + set the value of &PATH;, + the most straightforward way is probably: + + </para> + + <sconstruct> + env['ENV']['PATH'] = ['/usr/local/bin', '/bin', '/usr/bin'] + </sconstruct> + + <para> + + Note that &SCons; does allow you to define + the directories in the &PATH; in a string, + separated by the pathname-separator character + for your system (':' on POSIX systems, ';' on Windows): + + </para> + + <sconstruct> + env['ENV']['PATH'] = '/usr/local/bin:/bin:/usr/bin' + </sconstruct> + + <para> + + But doing so makes your &SConscript; file less portable, + (although in this case that may not be a huge concern + since the directories you list are likley system-specific, anyway). + + </para> + + <!-- + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Command('foo', [], '__ROOT__/usr/bin/printenv.py') + </file> + <file name="__ROOT__/usr/bin/printenv.py" chmod="0755"> + #!/usr/bin/env python + import os + import sys + if len(sys.argv) > 1: + keys = sys.argv[1:] + else: + keys = os.environ.keys() + keys.sort() + for key in keys: + print " " + key + "=" + os.environ[key] + </file> + </scons_example> + + <para> + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <section> + <title>Propagating &PATH; From the External Environment</title> + + <para> + + You may want to propagate the external &PATH; + to the execution environment for commands. + You do this by initializing the &PATH; + variable with the &PATH; value from + the <literal>os.environ</literal> + dictionary, + which is Python's way of letting you + get at the external environment: + + </para> + + <sconstruct> + import os + env = Environment(ENV = {'PATH' : os.environ['PATH']}) + </sconstruct> + + <para> + + Alternatively, you may find it easier + to just propagate the entire external + environment to the execution environment + for commands. + This is simpler to code than explicity + selecting the &PATH; value: + + </para> + + <sconstruct> + import os + env = Environment(ENV = os.environ) + </sconstruct> + + <para> + + Either of these will guarantee that + &SCons; will be able to execute + any command that you can execute from the command line. + The drawback is that the build can behave + differently if it's run by people with + different &PATH; values in their environment--for example, + if both the <literal>/bin</literal> and + <literal>/usr/local/bin</literal> directories + have different &cc; commands, + then which one will be used to compile programs + will depend on which directory is listed + first in the user's &PATH; variable. + + </para> + + </section> + + <section> + <title>Adding to <varname>PATH</varname> Values in the Execution Environment</title> + + <para> + + One of the most common requirements + for manipulating a variable in the execution environment + is to add one or more custom directories to a search + like the <envar>$PATH</envar> variable on Linux or POSIX systems, + or the <envar>%PATH%</envar> variable on Windows, + so that a locally-installed compiler or other utility + can be found when &SCons; tries to execute it to update a target. + &SCons; provides &PrependENVPath; and &AppendENVPath; functions + to make adding things to execution variables convenient. + You call these functions by specifying the variable + to which you want the value added, + and then value itself. + So to add some <filename>/usr/local</filename> directories + to the <envar>$PATH</envar> and <envar>$LIB</envar> variables, + you might: + + </para> + + <sconstruct> + env = Environment(ENV = os.environ) + env.PrependENVPath('PATH', '/usr/local/bin') + env.AppendENVPath('LIB', '/usr/local/lib') + </sconstruct> + + <para> + + Note that the added values are strings, + and if you want to add multiple directories to + a variable like <envar>$PATH</envar>, + you must include the path separate character + (<literal>:</literal> on Linux or POSIX, + <literal>;</literal> on Windows) + in the string. + + </para> + + </section> + + </section> diff --git a/doc/user/environments.xml b/doc/user/environments.xml new file mode 100644 index 0000000..b9a60b9 --- /dev/null +++ b/doc/user/environments.xml @@ -0,0 +1,1684 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 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 Windows 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 + +XXX DESCRIBE THE Literal() FUNCTION, TOO XXX + +=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. + +--> + + <para> + + An <literal>environment</literal> + is a collection of values that + can affect how a program executes. + &SCons; distinguishes between three + different types of environments + that can affect the behavior of &SCons; itself + (subject to the configuration in the &SConscript; files), + as well as the compilers and other tools it executes: + + </para> + + <variablelist> + + <varlistentry> + <term>External Environment</term> + + <listitem> + <para> + + The <literal>external environment</literal> + is the set of variables in the user's environment + at the time the user runs &SCons;. + These variables are available within the &SConscript; files + through the Python <literal>os.environ</literal> dictionary. + See <xref linkend="sect-external-environments"></xref>, below. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>&ConsEnv;</term> + + <listitem> + <para> + + A &consenv; + is a distinct object creating within + a &SConscript; file and + and which contains values that + affect how &SCons; decides + what action to use to build a target, + and even to define which targets + should be built from which sources. + One of the most powerful features of &SCons; + is the ability to create multiple &consenvs;, + including the ability to clone a new, customized + &consenv; from an existing &consenv;. + See <xref linkend="sect-construction-environments"></xref>, below. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Execution Environment</term> + + <listitem> + <para> + + An <literal>execution environment</literal> + is the values that &SCons; sets + when executing an external + command (such as a compiler or linker) + to build one or more targets. + Note that this is not the same as + the <literal>external environment</literal> + (see above). + See <xref linkend="sect-execution-environments"></xref>, below. + + </para> + </listitem> + </varlistentry> + + </variablelist> + + <para> + + Unlike &Make;, &SCons; does not automatically + copy or import values between different environments + (with the exception of explicit clones of &consenvs;, + which inherit values from their parent). + This is a deliberate design choice + to make sure that builds are, + by default, repeatable regardless of + the values in the user's external environment. + This avoids a whole class of problems with builds + where a developer's local build works + because a custom variable setting + causes a different compiler or build option to be used, + but the checked-in change breaks the official build + because it uses different environment variable settings. + + </para> + + <para> + + Note that the &SConscript; writer can + easily arrange for variables to be + copied or imported between environments, + and this is often very useful + (or even downright necessary) + to make it easy for developers + to customize the build in appropriate ways. + The point is <emphasis>not</emphasis> + that copying variables between different environments + is evil and must always be avoided. + Instead, it should be up to the + implementer of the build system + to make conscious choices + about how and when to import + a variable from one environment to another, + making informed decisions about + striking the right balance + between making the build + repeatable on the one hand + and convenient to use on the other. + + </para> + + <section id="sect-external-environments"> + <title>Using Values From the External Environment</title> + + <para> + + The <literal>external environment</literal> + variable settings that + the user has in force + when executing &SCons; + are available through the normal Python + <envar>os.environ</envar> + dictionary. + This means that you must add an + <literal>import os</literal> statement + to any &SConscript; file + in which you want to use + values from the user's external environment. + + </para> + + <programlisting> + import os + </programlisting> + + <para> + + More usefully, you can use the + <envar>os.environ</envar> + dictionary in your &SConscript; + files to initialize &consenvs; + with values from the user's external environment. + See the next section, + <xref linkend="sect-construction-environments"></xref>, + for information on how to do this. + + </para> + + </section> + + <section id="sect-construction-environments"> + <title>Construction Environments</title> + + <para> + + It is rare that all of the software in a large, + complicated system needs to be built the same way. + For example, different source files may need different options + enabled on the command line, + or different executable programs need to be linked + with different libraries. + &SCons; accommodates these different build + requirements by allowing you to create and + configure multiple &consenvs; + that control how the software is built. + A &consenv; is an object + that has a number of associated + &consvars;, each with a name and a value. + (A construction environment also has an attached + set of &Builder; methods, + about which we'll learn more later.) + + </para> + + <section> + <title>Creating a &ConsEnv;: the &Environment; Function</title> + + <para> + + A &consenv; is created by the &Environment; method: + + </para> + + <programlisting> + env = Environment() + </programlisting> + + <para> + + By default, &SCons; initializes every + new construction environment + with a set of &consvars; + based on the tools that it finds on your system, + plus the default set of builder methods + necessary for using those tools. + The construction variables + are initialized with values describing + the C compiler, + the Fortran compiler, + the linker, + etc., + as well as the command lines to invoke them. + + </para> + + <para> + + When you initialize a construction environment + you can set the values of the + environment's &consvars; + to control how a program is built. + For example: + + </para> + + <programlisting> + import os + + env = Environment(CC = 'gcc', + CCFLAGS = '-O2') + + env.Program('foo.c') + </programlisting> + + <para> + + The construction environment in this example + is still initialized with the same default + construction variable values, + except that the user has explicitly specified use of the + GNU C compiler &gcc;, + and further specifies that the <literal>-O2</literal> + (optimization level two) + flag should be used when compiling the object file. + In other words, the explicit initializations of + &cv-link-CC; and &cv-link-CCFLAGS; + override the default values in the newly-created + construction environment. + So a run from this example would look like: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + gcc -o foo.o -c -O2 foo.c + gcc -o foo foo.o + </screen> + + </section> + + <section> + <title>Fetching Values From a &ConsEnv;</title> + + <para> + + You can fetch individual construction variables + using the normal syntax + for accessing individual named items in a Python dictionary: + + </para> + + <programlisting> + env = Environment() + print "CC is:", env['CC'] + </programlisting> + + <para> + + This example &SConstruct; file doesn't build anything, + but because it's actually a Python script, + it will print the value of &cv-link-CC; for us: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + CC is: cc + scons: `.' is up to date. + </screen> + + <para> + + A construction environment, however, + is actually an object with associated methods, etc. + If you want to have direct access to only the + dictionary of construction variables, + you can fetch this using the &Dictionary; method: + + </para> + + <programlisting> + env = Environment(FOO = 'foo', BAR = 'bar') + dict = env.Dictionary() + for key in ['OBJSUFFIX', 'LIBSUFFIX', 'PROGSUFFIX']: + print "key = %s, value = %s" % (key, dict[key]) + </programlisting> + + <para> + + This &SConstruct; file + will print the specified dictionary items for us on POSIX + systems as follows: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + key = OBJSUFFIX, value = .o + key = LIBSUFFIX, value = .a + key = PROGSUFFIX, value = + scons: `.' is up to date. + </screen> + + <para> + + And on Windows: + + </para> + + <screen> + C:\><userinput>scons -Q</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + key = OBJSUFFIX, value = .obj + key = LIBSUFFIX, value = .lib + key = PROGSUFFIX, value = .exe + scons: `.' is up to date. + </screen> + + <para> + + If you want to loop and print the values of + all of the construction variables in a construction environment, + the Python code to do that in sorted order might look something like: + + </para> + + <programlisting> + env = Environment() + dict = env.Dictionary() + keys = dict.keys() + keys.sort() + for key in keys: + print "construction variable = '%s', value = '%s'" % (key, dict[key]) + </programlisting> + + </section> + + <section> + <title>Expanding Values From a &ConsEnv;: the &subst; Method</title> + + <para> + + Another way to get information from + a construction environment. + is to use the &subst; method + on a string containing <literal>$</literal> expansions + of construction variable names. + As a simple example, + the example from the previous + section that used + <literal>env['CC']</literal> + to fetch the value of &cv-link-CC; + could also be written as: + + </para> + + <programlisting> + env = Environment() + print "CC is:", env.subst('$CC') + </programlisting> + + <para> + + One advantage of using + &subst; to expand strings is + that construction variables + in the result get re-expanded until + there are no expansions left in the string. + So a simple fetch of a value like + &cv-link-CCCOM;: + + </para> + + <programlisting> + env = Environment(CCFLAGS = '-DFOO') + print "CCCOM is:", env['CCCOM'] + </programlisting> + + <para> + + Will print the unexpanded value of &cv-CCCOM;, + showing us the construction + variables that still need to be expanded: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + CCCOM is: $CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES + scons: `.' is up to date. + </screen> + + <para> + + Calling the &subst; method on <varname>$CCOM</varname>, + however: + + </para> + + <programlisting> + env = Environment(CCFLAGS = '-DFOO') + print "CCCOM is:", env.subst('$CCCOM') + </programlisting> + + <para> + + Will recursively expand all of + the construction variables prefixed + with <literal>$</literal> (dollar signs), + showing us the final output: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + CCCOM is: gcc -DFOO -c -o + scons: `.' is up to date. + </screen> + + <para> + + Note that because we're not expanding this + in the context of building something + there are no target or source files + for &cv-link-TARGET; and &cv-link-SOURCES; to expand. + + </para> + + </section> + + <section> + <title>Controlling the Default &ConsEnv;: the &DefaultEnvironment; Function</title> + + <para> + + All of the &Builder; functions that we've introduced so far, + like &Program; and &Library;, + actually use a default &consenv; + that contains settings + for the various compilers + and other tools that + &SCons; configures by default, + or otherwise knows about + and has discovered on your system. + The goal of the default construction environment + is to make many configurations to "just work" + to build software using + readily available tools + with a minimum of configuration changes. + + </para> + + <para> + + You can, however, control the settings + in the default contstruction environment + by using the &DefaultEnvironment; function + to initialize various settings: + + </para> + + <programlisting> + + DefaultEnvironment(CC = '/usr/local/bin/gcc') + + </programlisting> + + <para> + + When configured as above, + all calls to the &Program; + or &Object; Builder + will build object files with the + <filename>/usr/local/bin/gcc</filename> + compiler. + + </para> + + <para> + + Note that the &DefaultEnvironment; function + returns the initialized + default construction environment object, + which can then be manipulated like any + other construction environment. + So the following + would be equivalent to the + previous example, + setting the &cv-CC; + variable to <filename>/usr/local/bin/gcc</filename> + but as a separate step after + the default construction environment has been initialized: + + </para> + + <programlisting> + + env = DefaultEnvironment() + env['CC'] = '/usr/local/bin/gcc' + + </programlisting> + + <para> + + One very common use of the &DefaultEnvironment; function + is to speed up &SCons; initialization. + As part of trying to make most default + configurations "just work," + &SCons; will actually + search the local system for installed + compilers and other utilities. + This search can take time, + especially on systems with + slow or networked file systems. + If you know which compiler(s) and/or + other utilities you want to configure, + you can control the search + that &SCons; performs + by specifying some specific + tool modules with which to + initialize the default construction environment: + + </para> + + <programlisting> + + env = DefaultEnvironment(tools = ['gcc', 'gnulink'], + CC = '/usr/local/bin/gcc') + + </programlisting> + + <para> + + So the above example would tell &SCons; + to explicitly configure the default environment + to use its normal GNU Compiler and GNU Linker settings + (without having to search for them, + or any other utilities for that matter), + and specifically to use the compiler found at + <filename>/usr/local/bin/gcc</filename>. + + </para> + + </section> + + <section> + <title>Multiple &ConsEnvs;</title> + + <para> + + The real advantage of construction environments + is that you can create as many different construction + environments as you need, + each tailored to a different way to build + some piece of software or other file. + If, for example, we need to build + one program with the <literal>-O2</literal> flag + and another with the <literal>-g</literal> (debug) flag, + we would do this like so: + + </para> + + <programlisting> + opt = Environment(CCFLAGS = '-O2') + dbg = Environment(CCFLAGS = '-g') + + opt.Program('foo', 'foo.c') + + dbg.Program('bar', 'bar.c') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + cc -o bar.o -c -g bar.c + cc -o bar bar.o + cc -o foo.o -c -O2 foo.c + cc -o foo foo.o + </screen> + + <para> + + We can even use multiple construction environments to build + multiple versions of a single program. + If you do this by simply trying to use the + &b-link-Program; builder with both environments, though, + like this: + + </para> + + <programlisting> + opt = Environment(CCFLAGS = '-O2') + dbg = Environment(CCFLAGS = '-g') + + opt.Program('foo', 'foo.c') + + dbg.Program('foo', 'foo.c') + </programlisting> + + <para> + + Then &SCons; generates the following error: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + + scons: warning: Two different environments were specified for target foo.o, + but they appear to have the same action: CCCom(target, source, env) + File "/home/my/project/SConstruct", line 6, in ? + + scons: warning: Two different environments were specified for target foo, + but they appear to have the same action: Cat(target, source, env) + File "/home/my/project/SConstruct", line 6, in ? + cc -o foo.o -c -g foo.c + cc -o foo foo.o + </screen> + + <para> + + This is because the two &b-Program; calls have + each implicitly told &SCons; to generate an object file named + <filename>foo.o</filename>, + one with a &cv-link-CCFLAGS; value of + <literal>-O2</literal> + and one with a &cv-link-CCFLAGS; value of + <literal>-g</literal>. + &SCons; can't just decide that one of them + should take precedence over the other, + so it generates the error. + To avoid this problem, + we must explicitly specify + that each environment compile + <filename>foo.c</filename> + to a separately-named object file + using the &b-link-Object; builder, like so: + + </para> + + <programlisting> + opt = Environment(CCFLAGS = '-O2') + dbg = Environment(CCFLAGS = '-g') + + o = opt.Object('foo-opt', 'foo.c') + opt.Program(o) + + d = dbg.Object('foo-dbg', 'foo.c') + dbg.Program(d) + </programlisting> + + <para> + + Notice that each call to the &b-Object; builder + returns a value, + an internal &SCons; object that + represents the object file that will be built. + We then use that object + as input to the &b-Program; builder. + This avoids having to specify explicitly + the object file name in multiple places, + and makes for a compact, readable + &SConstruct; file. + Our &SCons; output then looks like: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o foo-dbg.o -c -g foo.c + cc -o foo-dbg foo-dbg.o + cc -o foo-opt.o -c -O2 foo.c + cc -o foo-opt foo-opt.o + </screen> + + </section> + + <section> + <title>Making Copies of &ConsEnvs;: the &Clone; Method</title> + + <para> + + Sometimes you want more than one construction environment + to share the same values for one or more variables. + Rather than always having to repeat all of the common + variables when you create each construction environment, + you can use the &Clone; method + to create a copy of a construction environment. + + </para> + + <para> + + Like the &Environment; call that creates a construction environment, + the &Clone; method takes &consvar; assignments, + which will override the values in the copied construction environment. + For example, suppose we want to use &gcc; + to create three versions of a program, + one optimized, one debug, and one with neither. + We could do this by creating a "base" construction environment + that sets &cv-link-CC; to &gcc;, + and then creating two copies, + one which sets &cv-link-CCFLAGS; for optimization + and the other which sets &cv-CCFLAGS; for debugging: + + </para> + + <programlisting> + env = Environment(CC = 'gcc') + opt = env.Clone(CCFLAGS = '-O2') + dbg = env.Clone(CCFLAGS = '-g') + + env.Program('foo', 'foo.c') + + o = opt.Object('foo-opt', 'foo.c') + opt.Program(o) + + d = dbg.Object('foo-dbg', 'foo.c') + dbg.Program(d) + </programlisting> + + <para> + + Then our output would look like: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + gcc -o foo.o -c foo.c + gcc -o foo foo.o + gcc -o foo-dbg.o -c -g foo.c + gcc -o foo-dbg foo-dbg.o + gcc -o foo-opt.o -c -O2 foo.c + gcc -o foo-opt foo-opt.o + </screen> + + </section> + + <section> + <title>Replacing Values: the &Replace; Method</title> + + <para> + + You can replace existing construction variable values + using the &Replace; method: + + </para> + + <programlisting> + env = Environment(CCFLAGS = '-DDEFINE1') + env.Replace(CCFLAGS = '-DDEFINE2') + env.Program('foo.c') + </programlisting> + + <para> + + The replacing value + (<literal>-DDEFINE2</literal> in the above example) + completely replaces the value in the + construction environment: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o foo.o -c -DDEFINE2 foo.c + cc -o foo foo.o + </screen> + + <para> + + You can safely call &Replace; + for construction variables that + don't exist in the construction environment: + + </para> + + <programlisting> + env = Environment() + env.Replace(NEW_VARIABLE = 'xyzzy') + print "NEW_VARIABLE =", env['NEW_VARIABLE'] + </programlisting> + + <para> + + In this case, + the construction variable simply + gets added to the construction environment: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + NEW_VARIABLE = xyzzy + scons: `.' is up to date. + </screen> + + <para> + + Because the variables + aren't expanded until the construction environment + is actually used to build the targets, + and because &SCons; function and method calls + are order-independent, + the last replacement "wins" + and is used to build all targets, + regardless of the order in which + the calls to Replace() are + interspersed with calls to + builder methods: + + </para> + + <programlisting> + env = Environment(CCFLAGS = '-DDEFINE1') + print "CCFLAGS =", env['CCFLAGS'] + env.Program('foo.c') + + env.Replace(CCFLAGS = '-DDEFINE2') + print "CCFLAGS =", env['CCFLAGS'] + env.Program('bar.c') + </programlisting> + + <para> + + The timing of when the replacement + actually occurs relative + to when the targets get built + becomes apparent + if we run &scons; without the <literal>-Q</literal> + option: + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + CCFLAGS = -DDEFINE1 + CCFLAGS = -DDEFINE2 + scons: done reading SConscript files. + scons: Building targets ... + cc -o bar.o -c -DDEFINE2 bar.c + cc -o bar bar.o + cc -o foo.o -c -DDEFINE2 foo.c + cc -o foo foo.o + scons: done building targets. + </screen> + + <para> + + Because the replacement occurs while + the &SConscript; files are being read, + the &cv-link-CCFLAGS; + variable has already been set to + <literal>-DDEFINE2</literal> + by the time the &foo_o; target is built, + even though the call to the &Replace; + method does not occur until later in + the &SConscript; file. + + </para> + + </section> + + <section> + <title>Setting Values Only If They're Not Already Defined: the &SetDefault; Method</title> + + <para> + + Sometimes it's useful to be able to specify + that a construction variable should be + set to a value only if the construction environment + does not already have that variable defined + You can do this with the &SetDefault; method, + which behaves similarly to the <function>set_default</function> + method of Python dictionary objects: + + </para> + + <programlisting> + env.SetDefault(SPECIAL_FLAG = '-extra-option') + </programlisting> + + <para> + + This is especially useful + when writing your own <literal>Tool</literal> modules + to apply variables to construction environments. + <!-- + See <xref linkend="chap-tool-modules"></xref> + for more information about writing + Tool modules. + --> + + </para> + + </section> + + <section> + <title>Appending to the End of Values: the &Append; Method</title> + + <para> + + You can append a value to + an existing construction variable + using the &Append; method: + + </para> + + <programlisting> + env = Environment(CCFLAGS = ['-DMY_VALUE']) + env.Append(CCFLAGS = ['-DLAST']) + env.Program('foo.c') + </programlisting> + + <para> + + &SCons; then supplies both the <literal>-DMY_VALUE</literal> and + <literal>-DLAST</literal> flags when compiling the object file: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o foo.o -c -DMY_VALUE -DLAST foo.c + cc -o foo foo.o + </screen> + + <para> + + If the construction variable doesn't already exist, + the &Append; method will create it: + + </para> + + <programlisting> + env = Environment() + env.Append(NEW_VARIABLE = 'added') + print "NEW_VARIABLE =", env['NEW_VARIABLE'] + </programlisting> + + <para> + + Which yields: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + NEW_VARIABLE = added + scons: `.' is up to date. + </screen> + + <para> + + Note that the &Append; function tries to be "smart" + about how the new value is appended to the old value. + If both are strings, the previous and new strings + are simply concatenated. + Similarly, if both are lists, + the lists are concatenated. + If, however, one is a string and the other is a list, + the string is added as a new element to the list. + + </para> + + </section> + + <section> + <title>Appending Unique Values: the &AppendUnique; Method</title> + + <para> + + Some times it's useful to add a new value + only if the existing construction variable + doesn't already contain the value. + This can be done using the &AppendUnique; method: + + </para> + + <programlisting> + env.AppendUnique(CCFLAGS=['-g']) + </programlisting> + + <para> + + In the above example, + the <literal>-g</literal> would be added + only if the &cv-CCFLAGS; variable + does not already contain a <literal>-g</literal> value. + + </para> + + </section> + + <section> + <title>Appending to the Beginning of Values: the &Prepend; Method</title> + + <para> + + You can append a value to the beginning of + an existing construction variable + using the &Prepend; method: + + </para> + + <programlisting> + env = Environment(CCFLAGS = ['-DMY_VALUE']) + env.Prepend(CCFLAGS = ['-DFIRST']) + env.Program('foo.c') + </programlisting> + + <para> + + &SCons; then supplies both the <literal>-DFIRST</literal> and + <literal>-DMY_VALUE</literal> flags when compiling the object file: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o foo.o -c -DFIRST -DMY_VALUE foo.c + cc -o foo foo.o + </screen> + + <para> + + If the construction variable doesn't already exist, + the &Prepend; method will create it: + + </para> + + <programlisting> + env = Environment() + env.Prepend(NEW_VARIABLE = 'added') + print "NEW_VARIABLE =", env['NEW_VARIABLE'] + </programlisting> + + <para> + + Which yields: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + NEW_VARIABLE = added + scons: `.' is up to date. + </screen> + + <para> + + Like the &Append; function, + the &Prepend; function tries to be "smart" + about how the new value is appended to the old value. + If both are strings, the previous and new strings + are simply concatenated. + Similarly, if both are lists, + the lists are concatenated. + If, however, one is a string and the other is a list, + the string is added as a new element to the list. + + </para> + + </section> + + <section> + <title>Prepending Unique Values: the &PrependUnique; Method</title> + + <para> + + Some times it's useful to add a new value + to the beginning of a construction variable + only if the existing value + doesn't already contain the to-be-added value. + This can be done using the &PrependUnique; method: + + </para> + + <programlisting> + env.PrependUnique(CCFLAGS=['-g']) + </programlisting> + + <para> + + In the above example, + the <literal>-g</literal> would be added + only if the &cv-CCFLAGS; variable + does not already contain a <literal>-g</literal> value. + + </para> + + </section> + + </section> + + <section id="sect-execution-environments"> + <title>Controlling the Execution Environment for Issued Commands</title> + + <para> + + When &SCons; builds a target file, + it does not execute the commands with + the same external environment + that you used to execute &SCons;. + Instead, it uses the dictionary + stored in the &cv-link-ENV; construction variable + as the external environment + for executing commands. + + </para> + + <para> + + The most important ramification of this behavior + is that the &PATH; environment variable, + which controls where the operating system + will look for commands and utilities, + is not the same as in the external environment + from which you called &SCons;. + This means that &SCons; will not, by default, + necessarily find all of the tools + that you can execute from the command line. + + </para> + + <para> + + The default value of the &PATH; environment variable + on a POSIX system + is <literal>/usr/local/bin:/bin:/usr/bin</literal>. + The default value of the &PATH; environment variable + on a Windows system comes from the Windows registry + value for the command interpreter. + If you want to execute any commands--compilers, linkers, etc.--that + are not in these default locations, + you need to set the &PATH; value + in the &cv-ENV; dictionary + in your construction environment. + + </para> + + <para> + + The simplest way to do this is to initialize explicitly + the value when you create the construction environment; + this is one way to do that: + + </para> + + <programlisting> + path = ['/usr/local/bin', '/bin', '/usr/bin'] + env = Environment(ENV = {'PATH' : path}) + </programlisting> + + <para> + + Assign a dictionary to the &cv-ENV; + construction variable in this way + completely resets the external environment + so that the only variable that will be + set when external commands are executed + will be the &PATH; value. + If you want to use the rest of + the values in &cv-ENV; and only + set the value of &PATH;, + the most straightforward way is probably: + + </para> + + <programlisting> + env['ENV']['PATH'] = ['/usr/local/bin', '/bin', '/usr/bin'] + </programlisting> + + <para> + + Note that &SCons; does allow you to define + the directories in the &PATH; in a string, + separated by the pathname-separator character + for your system (':' on POSIX systems, ';' on Windows): + + </para> + + <programlisting> + env['ENV']['PATH'] = '/usr/local/bin:/bin:/usr/bin' + </programlisting> + + <para> + + But doing so makes your &SConscript; file less portable, + (although in this case that may not be a huge concern + since the directories you list are likley system-specific, anyway). + + </para> + + <!-- + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Command('foo', [], '__ROOT__/usr/bin/printenv.py') + </file> + <file name="__ROOT__/usr/bin/printenv.py" chmod="0755"> + #!/usr/bin/env python + import os + import sys + if len(sys.argv) > 1: + keys = sys.argv[1:] + else: + keys = os.environ.keys() + keys.sort() + for key in keys: + print " " + key + "=" + os.environ[key] + </file> + </scons_example> + + <para> + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <section> + <title>Propagating &PATH; From the External Environment</title> + + <para> + + You may want to propagate the external &PATH; + to the execution environment for commands. + You do this by initializing the &PATH; + variable with the &PATH; value from + the <literal>os.environ</literal> + dictionary, + which is Python's way of letting you + get at the external environment: + + </para> + + <programlisting> + import os + env = Environment(ENV = {'PATH' : os.environ['PATH']}) + </programlisting> + + <para> + + Alternatively, you may find it easier + to just propagate the entire external + environment to the execution environment + for commands. + This is simpler to code than explicity + selecting the &PATH; value: + + </para> + + <programlisting> + import os + env = Environment(ENV = os.environ) + </programlisting> + + <para> + + Either of these will guarantee that + &SCons; will be able to execute + any command that you can execute from the command line. + The drawback is that the build can behave + differently if it's run by people with + different &PATH; values in their environment--for example, + if both the <literal>/bin</literal> and + <literal>/usr/local/bin</literal> directories + have different &cc; commands, + then which one will be used to compile programs + will depend on which directory is listed + first in the user's &PATH; variable. + + </para> + + </section> + + <section> + <title>Adding to <varname>PATH</varname> Values in the Execution Environment</title> + + <para> + + One of the most common requirements + for manipulating a variable in the execution environment + is to add one or more custom directories to a search + like the <envar>$PATH</envar> variable on Linux or POSIX systems, + or the <envar>%PATH%</envar> variable on Windows, + so that a locally-installed compiler or other utility + can be found when &SCons; tries to execute it to update a target. + &SCons; provides &PrependENVPath; and &AppendENVPath; functions + to make adding things to execution variables convenient. + You call these functions by specifying the variable + to which you want the value added, + and then value itself. + So to add some <filename>/usr/local</filename> directories + to the <envar>$PATH</envar> and <envar>$LIB</envar> variables, + you might: + + </para> + + <programlisting> + env = Environment(ENV = os.environ) + env.PrependENVPath('PATH', '/usr/local/bin') + env.AppendENVPath('LIB', '/usr/local/lib') + </programlisting> + + <para> + + Note that the added values are strings, + and if you want to add multiple directories to + a variable like <envar>$PATH</envar>, + you must include the path separate character + (<literal>:</literal> on Linux or POSIX, + <literal>;</literal> on Windows) + in the string. + + </para> + + </section> + + </section> diff --git a/doc/user/errors.in b/doc/user/errors.in new file mode 100644 index 0000000..0051953 --- /dev/null +++ b/doc/user/errors.in @@ -0,0 +1,41 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + XXX + + </para> + + <section> + <title>XXX</title> + + <para> + + XXX + + </para> + + </section> diff --git a/doc/user/errors.xml b/doc/user/errors.xml new file mode 100644 index 0000000..0051953 --- /dev/null +++ b/doc/user/errors.xml @@ -0,0 +1,41 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + XXX + + </para> + + <section> + <title>XXX</title> + + <para> + + XXX + + </para> + + </section> diff --git a/doc/user/example.in b/doc/user/example.in new file mode 100644 index 0000000..0051953 --- /dev/null +++ b/doc/user/example.in @@ -0,0 +1,41 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + XXX + + </para> + + <section> + <title>XXX</title> + + <para> + + XXX + + </para> + + </section> diff --git a/doc/user/example.xml b/doc/user/example.xml new file mode 100644 index 0000000..0051953 --- /dev/null +++ b/doc/user/example.xml @@ -0,0 +1,41 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + XXX + + </para> + + <section> + <title>XXX</title> + + <para> + + XXX + + </para> + + </section> diff --git a/doc/user/factories.in b/doc/user/factories.in new file mode 100644 index 0000000..0cea6c4 --- /dev/null +++ b/doc/user/factories.in @@ -0,0 +1,507 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; provides a number of platform-independent functions, + called <literal>factories</literal>, + that perform common file system manipulations + like copying, moving or deleting files and directories, + or making directories. + These functions are <literal>factories</literal> + because they don't perform the action + at the time they're called, + they each return an &Action; object + that can be executed at the appropriate time. + + </para> + + <section> + <title>Copying Files or Directories: The &Copy; Factory</title> + + <para> + + Suppose you want to arrange to make a copy of a file, + and don't have a suitable pre-existing builder. + <footnote> + <para> + Unfortunately, in the early days of SCons design, + we used the name &Copy; for the function that + returns a copy of the environment, + otherwise that would be the logical choice for + a Builder that copies a file or directory tree + to a target location. + </para> + </footnote> + One way would be to use the &Copy; action factory + in conjunction with the &Command; builder: + + </para> + + <scons_example name="Copy1"> + <file name="SConstruct" printme="1"> + Command("file.out", "file.in", Copy("$TARGET", "$SOURCE")) + </file> + <file name="file.in">file.in</file> + </scons_example> + + <para> + + Notice that the action returned by the &Copy; factory + will expand the &cv-link-TARGET; and &cv-link-SOURCE; strings + at the time &file_out; is built, + and that the order of the arguments + is the same as that of a builder itself--that is, + target first, followed by source: + + </para> + + <scons_output example="Copy1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + You can, of course, name a file explicitly + instead of using &cv-TARGET; or &cv-SOURCE;: + + </para> + + <scons_example name="Copy2"> + <file name="SConstruct" printme="1"> + Command("file.out", [], Copy("$TARGET", "file.in")) + </file> + <file name="file.in">file.in</file> + </scons_example> + + <para> + + Which executes as: + + </para> + + <scons_output example="Copy2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + The usefulness of the &Copy; factory + becomes more apparent when + you use it in a list of actions + passed to the &Command; builder. + For example, suppose you needed to run a + file through a utility that only modifies files in-place, + and can't "pipe" input to output. + One solution is to copy the source file + to a temporary file name, + run the utility, + and then copy the modified temporary file to the target, + which the &Copy; factory makes extremely easy: + + </para> + + <scons_example name="Copy3"> + <file name="S" printme="1"> + Command("file.out", "file.in", + [ + Copy("tempfile", "$SOURCE"), + "modify tempfile", + Copy("$TARGET", "tempfile"), + ]) + </file> + <file name="SConstruct"> + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + </file> + <file name="file.in">file.in</file> + <file name="modify" chmod="0755"> + touch $* + </file> + </scons_example> + + <para> + + The output then looks like: + + </para> + + <scons_output example="Copy3"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Deleting Files or Directories: The &Delete; Factory</title> + + <para> + + If you need to delete a file, + then the &Delete; factory + can be used in much the same way as + the &Copy; factory. + For example, if we want to make sure that + the temporary file + in our last example doesn't exist before + we copy to it, + we could add &Delete; to the beginning + of the command list: + + </para> + + <scons_example name="Delete1"> + <file name="S" printme="1"> + Command("file.out", "file.in", + [ + Delete("tempfile"), + Copy("tempfile", "$SOURCE"), + "modify tempfile", + Copy("$TARGET", "tempfile"), + ]) + </file> + <file name="SConstruct"> + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + </file> + <file name="file.in">file.in</file> + <file name="modify" chmod="0755"> + touch $* + </file> + </scons_example> + + <para> + + Which then executes as follows: + + </para> + + <scons_output example="Delete1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Of course, like all of these &Action; factories, + the &Delete factory also expands + &cv-link-TARGET; and &cv-link-SOURCE; variables appropriately. + For example: + + </para> + + <scons_example name="Delete2"> + <file name="SConstruct" printme="1"> + Command("file.out", "file.in", + [ + Delete("$TARGET"), + Copy("$TARGET", "$SOURCE") + ]) + </file> + <file name="file.in">file.in</file> + </scons_example> + + <para> + + Executes as: + + </para> + + <scons_output example="Delete2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Note, however, that you typically don't need to + call the &Delete; factory explicitly in this way; + by default, &SCons; deletes its target(s) + for you before executing any action. + + </para> + + <para> + + One word of caution about using the &Delete; factory: + it has the same variable expansions available + as any other factory, including the &cv-SOURCE; variable. + Specifying <literal>Delete("$SOURCE")</literal> + is not something you usually want to do! + + </para> + + </section> + + <section> + <title>Moving (Renaming) Files or Directories: The &Move; Factory</title> + + <para> + + The &Move; factory + allows you to rename a file or directory. + For example, if we don't want to copy the temporary file, + we could use: + + </para> + + <scons_example name="Move"> + <file name="S" printme="1"> + Command("file.out", "file.in", + [ + Copy("tempfile", "$SOURCE"), + "modify tempfile", + Move("$TARGET", "tempfile"), + ]) + </file> + <file name="SConstruct"> + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + </file> + <file name="file.in">file.in</file> + <file name="modify" chmod="0755"> + touch $* + </file> + </scons_example> + + <para> + + Which would execute as: + + </para> + + <scons_output example="Move"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Updating the Modification Time of a File: The &Touch; Factory</title> + + <para> + + If you just need to update the + recorded modification time for a file, + use the &Touch; factory: + + </para> + + <scons_example name="Touch"> + <file name="S" printme="1"> + Command("file.out", "file.in", + [ + Copy("$TARGET", "$SOURCE"), + Touch("$TARGET"), + ]) + </file> + <file name="SConstruct"> + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + </file> + <file name="file.in">file.in</file> + </scons_example> + + <para> + + Which executes as: + + </para> + + <scons_output example="Touch"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Creating a Directory: The &Mkdir; Factory</title> + + <para> + + If you need to create a directory, + use the &Mkdir; factory. + For example, if we need to process + a file in a temporary directory + in which the processing tool + will create other files that we don't care about, + you could use: + + </para> + + <scons_example name="Mkdir"> + <file name="S" printme="1"> + Command("file.out", "file.in", + [ + Delete("tempdir"), + Mkdir("tempdir"), + Copy("tempdir/${SOURCE.file}", "$SOURCE"), + "process tempdir", + Move("$TARGET", "tempdir/output_file"), + Delete("tempdir"), + ]) + </file> + <file name="SConstruct"> + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + </file> + <file name="file.in">file.in</file> + <file name="process" chmod="0755"> + touch $* + </file> + </scons_example> + + <para> + + Which executes as: + + </para> + + <scons_output example="Mkdir"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Changing File or Directory Permissions: The &Chmod; Factory</title> + + <para> + + To change permissions on a file or directory, + use the &Chmod; factory. + The permission argument uses POSIX-style + permission bits and should typically + be expressed as an octal, + not decimal, number: + + </para> + + <scons_example name="Chmod"> + <file name="SConstruct" printme="1"> + Command("file.out", "file.in", + [ + Copy("$TARGET", "$SOURCE"), + Chmod("$TARGET", 0755), + ]) + </file> + <file name="file.in">file.in</file> + </scons_example> + + <para> + + Which executes: + + </para> + + <scons_output example="Chmod"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Executing an action immediately: the &Execute; Function</title> + + <para> + + We've been showing you how to use &Action; factories + in the &Command; function. + You can also execute an &Action; returned by a factory + (or actually, any &Action;) + at the time the &SConscript; file is read + by using the &Execute; function. + For example, if we need to make sure that + a directory exists before we build any targets, + + </para> + + <scons_example name="Execute"> + <file name="SConstruct" printme="1"> + Execute(Mkdir('__ROOT__/tmp/my_temp_directory')) + </file> + </scons_example> + + <para> + + Notice that this will + create the directory while + the &SConscript; file is being read: + + </para> + + <scons_output example="Execute"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + If you're familiar with Python, + you may wonder why you would want to use this + instead of just calling the native Python + <function>os.mkdir()</function> function. + The advantage here is that the &Mkdir; + action will behave appropriately if the user + specifies the &SCons; <option>-n</option> or + <option>-q</option> options--that is, + it will print the action but not actually + make the directory when <option>-n</option> is specified, + or make the directory but not print the action + when <option>-q</option> is specified. + + </para> + + <para> + + The &Execute; function returns the exit status + or return value of the underlying action being executed. + It will also print an error message if the action + fails and returns a non-zero value. + &SCons; will <emphasis>not</emphasis>, however, + actually stop the build if the action fails. + If you want the build to stop + in response to a failure in an action called by &Execute;, + you must do so by explicitly + checking the return value + and calling the &Exit; function + (or a Python equivalent): + + </para> + + <sconstruct> + if Execute(Mkdir('__ROOT__/tmp/my_temp_directory')): + # A problem occurred while making the temp directory. + Exit(1) + </sconstruct> + + </section> diff --git a/doc/user/factories.xml b/doc/user/factories.xml new file mode 100644 index 0000000..17e52bd --- /dev/null +++ b/doc/user/factories.xml @@ -0,0 +1,466 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; provides a number of platform-independent functions, + called <literal>factories</literal>, + that perform common file system manipulations + like copying, moving or deleting files and directories, + or making directories. + These functions are <literal>factories</literal> + because they don't perform the action + at the time they're called, + they each return an &Action; object + that can be executed at the appropriate time. + + </para> + + <section> + <title>Copying Files or Directories: The &Copy; Factory</title> + + <para> + + Suppose you want to arrange to make a copy of a file, + and don't have a suitable pre-existing builder. + <footnote> + <para> + Unfortunately, in the early days of SCons design, + we used the name &Copy; for the function that + returns a copy of the environment, + otherwise that would be the logical choice for + a Builder that copies a file or directory tree + to a target location. + </para> + </footnote> + One way would be to use the &Copy; action factory + in conjunction with the &Command; builder: + + </para> + + <programlisting> + Command("file.out", "file.in", Copy("$TARGET", "$SOURCE")) + </programlisting> + + <para> + + Notice that the action returned by the &Copy; factory + will expand the &cv-link-TARGET; and &cv-link-SOURCE; strings + at the time &file_out; is built, + and that the order of the arguments + is the same as that of a builder itself--that is, + target first, followed by source: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + Copy("file.out", "file.in") + </screen> + + <para> + + You can, of course, name a file explicitly + instead of using &cv-TARGET; or &cv-SOURCE;: + + </para> + + <programlisting> + Command("file.out", [], Copy("$TARGET", "file.in")) + </programlisting> + + <para> + + Which executes as: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + Copy("file.out", "file.in") + </screen> + + <para> + + The usefulness of the &Copy; factory + becomes more apparent when + you use it in a list of actions + passed to the &Command; builder. + For example, suppose you needed to run a + file through a utility that only modifies files in-place, + and can't "pipe" input to output. + One solution is to copy the source file + to a temporary file name, + run the utility, + and then copy the modified temporary file to the target, + which the &Copy; factory makes extremely easy: + + </para> + + <programlisting> + Command("file.out", "file.in", + [ + Copy("tempfile", "$SOURCE"), + "modify tempfile", + Copy("$TARGET", "tempfile"), + ]) + </programlisting> + + <para> + + The output then looks like: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + Copy("tempfile", "file.in") + modify tempfile + Copy("file.out", "tempfile") + </screen> + + </section> + + <section> + <title>Deleting Files or Directories: The &Delete; Factory</title> + + <para> + + If you need to delete a file, + then the &Delete; factory + can be used in much the same way as + the &Copy; factory. + For example, if we want to make sure that + the temporary file + in our last example doesn't exist before + we copy to it, + we could add &Delete; to the beginning + of the command list: + + </para> + + <programlisting> + Command("file.out", "file.in", + [ + Delete("tempfile"), + Copy("tempfile", "$SOURCE"), + "modify tempfile", + Copy("$TARGET", "tempfile"), + ]) + </programlisting> + + <para> + + Which then executes as follows: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + Delete("tempfile") + Copy("tempfile", "file.in") + modify tempfile + Copy("file.out", "tempfile") + </screen> + + <para> + + Of course, like all of these &Action; factories, + the &Delete; factory also expands + &cv-link-TARGET; and &cv-link-SOURCE; variables appropriately. + For example: + + </para> + + <programlisting> + Command("file.out", "file.in", + [ + Delete("$TARGET"), + Copy("$TARGET", "$SOURCE") + ]) + </programlisting> + + <para> + + Executes as: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + Delete("file.out") + Copy("file.out", "file.in") + </screen> + + <para> + + Note, however, that you typically don't need to + call the &Delete; factory explicitly in this way; + by default, &SCons; deletes its target(s) + for you before executing any action. + + </para> + + <para> + + One word of caution about using the &Delete; factory: + it has the same variable expansions available + as any other factory, including the &cv-SOURCE; variable. + Specifying <literal>Delete("$SOURCE")</literal> + is not something you usually want to do! + + </para> + + </section> + + <section> + <title>Moving (Renaming) Files or Directories: The &Move; Factory</title> + + <para> + + The &Move; factory + allows you to rename a file or directory. + For example, if we don't want to copy the temporary file, + we could use: + + </para> + + <programlisting> + Command("file.out", "file.in", + [ + Copy("tempfile", "$SOURCE"), + "modify tempfile", + Move("$TARGET", "tempfile"), + ]) + </programlisting> + + <para> + + Which would execute as: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + Copy("tempfile", "file.in") + modify tempfile + Move("file.out", "tempfile") + </screen> + + </section> + + <section> + <title>Updating the Modification Time of a File: The &Touch; Factory</title> + + <para> + + If you just need to update the + recorded modification time for a file, + use the &Touch; factory: + + </para> + + <programlisting> + Command("file.out", "file.in", + [ + Copy("$TARGET", "$SOURCE"), + Touch("$TARGET"), + ]) + </programlisting> + + <para> + + Which executes as: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + Copy("file.out", "file.in") + Touch("file.out") + </screen> + + </section> + + <section> + <title>Creating a Directory: The &Mkdir; Factory</title> + + <para> + + If you need to create a directory, + use the &Mkdir; factory. + For example, if we need to process + a file in a temporary directory + in which the processing tool + will create other files that we don't care about, + you could use: + + </para> + + <programlisting> + Command("file.out", "file.in", + [ + Delete("tempdir"), + Mkdir("tempdir"), + Copy("tempdir/${SOURCE.file}", "$SOURCE"), + "process tempdir", + Move("$TARGET", "tempdir/output_file"), + Delete("tempdir"), + ]) + </programlisting> + + <para> + + Which executes as: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + Delete("tempdir") + Mkdir("tempdir") + Copy("tempdir/file.in", "file.in") + process tempdir + Move("file.out", "tempdir/output_file") + scons: *** [file.out] tempdir/output_file: No such file or directory + </screen> + + </section> + + <section> + <title>Changing File or Directory Permissions: The &Chmod; Factory</title> + + <para> + + To change permissions on a file or directory, + use the &Chmod; factory. + The permission argument uses POSIX-style + permission bits and should typically + be expressed as an octal, + not decimal, number: + + </para> + + <programlisting> + Command("file.out", "file.in", + [ + Copy("$TARGET", "$SOURCE"), + Chmod("$TARGET", 0755), + ]) + </programlisting> + + <para> + + Which executes: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + Copy("file.out", "file.in") + Chmod("file.out", 0755) + </screen> + + </section> + + <section> + <title>Executing an action immediately: the &Execute; Function</title> + + <para> + + We've been showing you how to use &Action; factories + in the &Command; function. + You can also execute an &Action; returned by a factory + (or actually, any &Action;) + at the time the &SConscript; file is read + by using the &Execute; function. + For example, if we need to make sure that + a directory exists before we build any targets, + + </para> + + <programlisting> + Execute(Mkdir('/tmp/my_temp_directory')) + </programlisting> + + <para> + + Notice that this will + create the directory while + the &SConscript; file is being read: + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + Mkdir("/tmp/my_temp_directory") + scons: done reading SConscript files. + scons: Building targets ... + scons: `.' is up to date. + scons: done building targets. + </screen> + + <para> + + If you're familiar with Python, + you may wonder why you would want to use this + instead of just calling the native Python + <function>os.mkdir()</function> function. + The advantage here is that the &Mkdir; + action will behave appropriately if the user + specifies the &SCons; <option>-n</option> or + <option>-q</option> options--that is, + it will print the action but not actually + make the directory when <option>-n</option> is specified, + or make the directory but not print the action + when <option>-q</option> is specified. + + </para> + + <para> + + The &Execute; function returns the exit status + or return value of the underlying action being executed. + It will also print an error message if the action + fails and returns a non-zero value. + &SCons; will <emphasis>not</emphasis>, however, + actually stop the build if the action fails. + If you want the build to stop + in response to a failure in an action called by &Execute;, + you must do so by explicitly + checking the return value + and calling the &Exit; function + (or a Python equivalent): + + </para> + + <programlisting> + if Execute(Mkdir('/tmp/my_temp_directory')): + # A problem occurred while making the temp directory. + Exit(1) + </programlisting> + + </section> diff --git a/doc/user/file-removal.in b/doc/user/file-removal.in new file mode 100644 index 0000000..c26f020 --- /dev/null +++ b/doc/user/file-removal.in @@ -0,0 +1,223 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + There are two occasions when &SCons; will, + by default, remove target files. + The first is when &SCons; determines that + an target file needs to be rebuilt + and removes the existing version of the target + before executing + The second is when &SCons; is invoked with the + <literal>-c</literal> option to "clean" + a tree of its built targets. + + These behaviours can be suppressed with the + &Precious; and &NoClean; functions, respectively. + + </para> + + <section> + <title>Preventing target removal during build: the &Precious; Function</title> + + <para> + + By default, &SCons; removes targets before building them. + Sometimes, however, this is not what you want. + For example, you may want to update a library incrementally, + not by having it deleted and then rebuilt from all + of the constituent object files. + In such cases, you can use the + &Precious; method to prevent + &SCons; from removing the target before it is built: + + </para> + + <scons_example name="precious-ex1"> + <file name="SConstruct" printme="1"> + env = Environment(RANLIBCOM='') + lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) + env.Precious(lib) + </file> + <file name="f1.c"> + int f1() { } + </file> + <file name="f2.c"> + int f2() { } + </file> + <file name="f3.c"> + int f3() { } + </file> + </scons_example> + + <para> + + Although the output doesn't look any different, + &SCons; does not, in fact, + delete the target library before rebuilding it: + + </para> + + <scons_output example="precious-ex1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + &SCons; will, however, still delete files marked as &Precious; + when the <literal>-c</literal> option is used. + + </para> + + </section> + + <section> + <title>Preventing target removal during clean: the &NoClean; Function</title> + + <para> + + By default, &SCons; removes all built targets when invoked + with the <literal>-c</literal> option to clean a source tree + of built targets. + Sometimes, however, this is not what you want. + For example, you may want to remove only intermediate generated files + (such as object files), + but leave the final targets + (the libraries) + untouched. + + In such cases, you can use the &NoClean; method to prevent &SCons; + from removing a target during a clean: + + </para> + + <scons_example name="noclean-ex1"> + <file name="SConstruct" printme="1"> + env = Environment(RANLIBCOM='') + lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) + env.NoClean(lib) + </file> + <file name="f1.c"> + int f1() { } + </file> + <file name="f2.c"> + int f2() { } + </file> + <file name="f3.c"> + int f3() { } + </file> + </scons_example> + + <para> + + Notice that the <filename>libfoo.a</filename> + is not listed as a removed file: + + </para> + + <scons_output example="noclean-ex1"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -c</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Removing additional files during clean: the &Clean; Function</title> + + <para> + + There may be additional files that you want removed + when the <literal>-c</literal> option is used, + but which &SCons; doesn't know about + because they're not normal target files. + For example, perhaps a command you invoke + creates a log file as + part of building the target file you want. + You would like the log file cleaned, + but you don't want to have to teach + SCons that the command + "builds" two files. + + </para> + + <para> + + You can use the &Clean; function to arrange for additional files + to be removed when the <literal>-c</literal> option is used. + Notice, however, that the &Clean; function takes two arguments, + and the <emphasis>second</emphasis> argument + is the name of the additional file you want cleaned + (<filename>foo.log</filename> in this example): + + </para> + + <scons_example name="clean-ex1"> + <file name="S" printme="1"> + t = Command('foo.out', 'foo.in', 'build -o $TARGET $SOURCE') + Clean(t, 'foo.log') + </file> + <file name="SConstruct"> + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + </file> + <file name="foo.in"> + foo.in + </file> + <file name="foo.log"> + foo.log + </file> + <file name="build" chmod="0755"> + cat $3 > $2 + </file> + </scons_example> + + <para> + + The first argument is the target with which you want + the cleaning of this additional file associated. + In the above example, + we've used the return value from the + &Command; function, + which represents the + <filename>foo.out</filename> + target. + Now whenever the + <filename>foo.out</filename> target is cleaned + by the <literal>-c</literal> option, + the <filename>foo.log</filename> file + will be removed as well: + + </para> + + <scons_output example="clean-ex1"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q -c</scons_output_command> + </scons_output> + + </section> diff --git a/doc/user/file-removal.xml b/doc/user/file-removal.xml new file mode 100644 index 0000000..542fd38 --- /dev/null +++ b/doc/user/file-removal.xml @@ -0,0 +1,202 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + There are two occasions when &SCons; will, + by default, remove target files. + The first is when &SCons; determines that + an target file needs to be rebuilt + and removes the existing version of the target + before executing + The second is when &SCons; is invoked with the + <literal>-c</literal> option to "clean" + a tree of its built targets. + + These behaviours can be suppressed with the + &Precious; and &NoClean; functions, respectively. + + </para> + + <section> + <title>Preventing target removal during build: the &Precious; Function</title> + + <para> + + By default, &SCons; removes targets before building them. + Sometimes, however, this is not what you want. + For example, you may want to update a library incrementally, + not by having it deleted and then rebuilt from all + of the constituent object files. + In such cases, you can use the + &Precious; method to prevent + &SCons; from removing the target before it is built: + + </para> + + <programlisting> + env = Environment(RANLIBCOM='') + lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) + env.Precious(lib) + </programlisting> + + <para> + + Although the output doesn't look any different, + &SCons; does not, in fact, + delete the target library before rebuilding it: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o f1.o -c f1.c + cc -o f2.o -c f2.c + cc -o f3.o -c f3.c + ar rc libfoo.a f1.o f2.o f3.o + </screen> + + <para> + + &SCons; will, however, still delete files marked as &Precious; + when the <literal>-c</literal> option is used. + + </para> + + </section> + + <section> + <title>Preventing target removal during clean: the &NoClean; Function</title> + + <para> + + By default, &SCons; removes all built targets when invoked + with the <literal>-c</literal> option to clean a source tree + of built targets. + Sometimes, however, this is not what you want. + For example, you may want to remove only intermediate generated files + (such as object files), + but leave the final targets + (the libraries) + untouched. + + In such cases, you can use the &NoClean; method to prevent &SCons; + from removing a target during a clean: + + </para> + + <programlisting> + env = Environment(RANLIBCOM='') + lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) + env.NoClean(lib) + </programlisting> + + <para> + + Notice that the <filename>libfoo.a</filename> + is not listed as a removed file: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o f1.o -c f1.c + cc -o f2.o -c f2.c + cc -o f3.o -c f3.c + ar rc libfoo.a f1.o f2.o f3.o + % <userinput>scons -c</userinput> + scons: Reading SConscript files ... + scons: done reading SConscript files. + scons: Cleaning targets ... + Removed f1.o + Removed f2.o + Removed f3.o + scons: done cleaning targets. + </screen> + + </section> + + <section> + <title>Removing additional files during clean: the &Clean; Function</title> + + <para> + + There may be additional files that you want removed + when the <literal>-c</literal> option is used, + but which &SCons; doesn't know about + because they're not normal target files. + For example, perhaps a command you invoke + creates a log file as + part of building the target file you want. + You would like the log file cleaned, + but you don't want to have to teach + SCons that the command + "builds" two files. + + </para> + + <para> + + You can use the &Clean; function to arrange for additional files + to be removed when the <literal>-c</literal> option is used. + Notice, however, that the &Clean; function takes two arguments, + and the <emphasis>second</emphasis> argument + is the name of the additional file you want cleaned + (<filename>foo.log</filename> in this example): + + </para> + + <programlisting> + t = Command('foo.out', 'foo.in', 'build -o $TARGET $SOURCE') + Clean(t, 'foo.log') + </programlisting> + + <para> + + The first argument is the target with which you want + the cleaning of this additional file associated. + In the above example, + we've used the return value from the + &Command; function, + which represents the + <filename>foo.out</filename> + target. + Now whenever the + <filename>foo.out</filename> target is cleaned + by the <literal>-c</literal> option, + the <filename>foo.log</filename> file + will be removed as well: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + build -o foo.out foo.in + % <userinput>scons -Q -c</userinput> + Removed foo.out + Removed foo.log + </screen> + + </section> diff --git a/doc/user/hierarchy.in b/doc/user/hierarchy.in new file mode 100644 index 0000000..a917d10 --- /dev/null +++ b/doc/user/hierarchy.in @@ -0,0 +1,794 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 Build command + +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 + +(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> + + The source code for large software projects + rarely stays in a single directory, + but is nearly always divided into a + hierarchy of directories. + Organizing a large software build using &SCons; + involves creating a hierarchy of build scripts + using the &SConscript; function. + + </para> + + <section> + <title>&SConscript; Files</title> + + <para> + + As we've already seen, + the build script at the top of the tree is called &SConstruct;. + The top-level &SConstruct; file can + use the &SConscript; function to + include other subsidiary scripts in the build. + These subsidiary scripts can, in turn, + use the &SConscript; function + to include still other scripts in the build. + By convention, these subsidiary scripts are usually + named &SConscript;. + For example, a top-level &SConstruct; file might + arrange for four subsidiary scripts to be included + in the build as follows: + + </para> + + <sconstruct> + SConscript(['drivers/display/SConscript', + 'drivers/mouse/SConscript', + 'parser/SConscript', + 'utilities/SConscript']) + </sconstruct> + + <para> + + In this case, the &SConstruct; file + lists all of the &SConscript; files in the build explicitly. + (Note, however, that not every directory in the tree + necessarily has an &SConscript; file.) + Alternatively, the <literal>drivers</literal> + subdirectory might contain an intermediate + &SConscript; file, + in which case the &SConscript; call in + the top-level &SConstruct; file + would look like: + + </para> + + <sconstruct> + SConscript(['drivers/SConscript', + 'parser/SConscript', + 'utilities/SConscript']) + </sconstruct> + + <para> + + And the subsidiary &SConscript; file in the + <literal>drivers</literal> subdirectory + would look like: + + </para> + + <sconstruct> + SConscript(['display/SConscript', + 'mouse/SConscript']) + </sconstruct> + + <para> + + Whether you list all of the &SConscript; files in the + top-level &SConstruct; file, + or place a subsidiary &SConscript; file in + intervening directories, + or use some mix of the two schemes, + is up to you and the needs of your software. + + </para> + + </section> + + <section> + <title>Path Names Are Relative to the &SConscript; Directory</title> + + <para> + + Subsidiary &SConscript; files make it easy to create a build + hierarchy because all of the file and directory names + in a subsidiary &SConscript; files are interpreted + relative to the directory in which the &SConscript; file lives. + Typically, this allows the &SConscript; file containing the + instructions to build a target file + to live in the same directory as the source files + from which the target will be built, + making it easy to update how the software is built + whenever files are added or deleted + (or other changes are made). + + </para> + + <para> + + For example, suppose we want to build two programs + &prog1; and &prog2; in two separate directories + with the same names as the programs. + One typical way to do this would be + with a top-level &SConstruct; file like this: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + SConscript(['prog1/SConscript', + 'prog2/SConscript']) + </file> + <file name="prog1/SConscript"> + env = Environment() + env.Program('prog1', ['main.c', 'foo1.c', 'foo2.c']) + </file> + <file name="prog2/SConscript"> + env = Environment() + env.Program('prog2', ['main.c', 'bar1.c', 'bar2.c']) + </file> + <directory name="prog1"></directory> + <file name="prog1/main.c"> + x + </file> + <file name="prog1/foo1.c"> + x + </file> + <file name="prog1/foo2.c"> + x + </file> + <directory name="prog2"></directory> + <file name="prog2/main.c"> + x + </file> + <file name="prog2/bar1.c"> + x + </file> + <file name="prog2/bar2.c"> + x + </file> + </scons_example> + + <para> + + And subsidiary &SConscript; files that look like this: + + </para> + + <scons_example_file example="ex1" name="prog1/SConscript"> + </scons_example_file> + + <para> + + And this: + + </para> + + <scons_example_file example="ex1" name="prog2/SConscript"> + </scons_example_file> + + <para> + + Then, when we run &SCons; in the top-level directory, + our build looks like: + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Notice the following: + + First, you can have files with the same names + in multiple directories, like main.c in the above example. + + Second, unlike standard recursive use of &Make;, + &SCons; stays in the top-level directory + (where the &SConstruct; file lives) + and issues commands that use the path names + from the top-level directory to the + target and source files within the hierarchy. + + </para> + + </section> + + <section> + <title>Top-Level Path Names in Subsidiary &SConscript; Files</title> + + <para> + + If you need to use a file from another directory, + it's sometimes more convenient to specify + the path to a file in another directory + from the top-level &SConstruct; directory, + even when you're using that file in + a subsidiary &SConscript; file in a subdirectory. + You can tell &SCons; to interpret a path name + as relative to the top-level &SConstruct; directory, + not the local directory of the &SConscript; file, + by appending a &hash; (hash mark) + to the beginning of the path name: + + </para> + + <scons_example name="ex2"> + <file name="SConstruct"> + SConscript('src/prog/SConscript') + </file> + <file name="src/prog/SConscript" printme="1"> + env = Environment() + env.Program('prog', ['main.c', '#lib/foo1.c', 'foo2.c']) + </file> + <file name="src/prog/main.c"> + x + </file> + <file name="lib/foo1.c"> + x + </file> + <file name="src/prog/foo2.c"> + x + </file> + </scons_example> + + <para> + + In this example, + the <literal>lib</literal> directory is + directly underneath the top-level &SConstruct; directory. + If the above &SConscript; file is in a subdirectory + named <literal>src/prog</literal>, + the output would look like: + + </para> + + <scons_output example="ex2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + (Notice that the <literal>lib/foo1.o</literal> object file + is built in the same directory as its source file. + See <xref linkend="chap-separate"></xref>, below, + for information about + how to build the object file in a different subdirectory.) + + </para> + + </section> + + <section> + <title>Absolute Path Names</title> + + <para> + + Of course, you can always specify + an absolute path name for a file--for example: + + </para> + + <scons_example name="ex3"> + <file name="SConstruct"> + SConscript('src/prog/SConscript') + </file> + <file name="src/prog/SConscript" printme="1"> + env = Environment() + env.Program('prog', ['main.c', '__ROOT__/usr/joe/lib/foo1.c', 'foo2.c']) + </file> + <file name="src/prog/main.c"> + x + </file> + <file name="__ROOT__/usr/joe/lib/foo1.c"> + x + </file> + <file name="src/prog/foo2.c"> + x + </file> + </scons_example> + + <para> + + Which, when executed, would yield: + + </para> + + <scons_output example="ex3"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + (As was the case with top-relative path names, + notice that the <literal>/usr/joe/lib/foo1.o</literal> object file + is built in the same directory as its source file. + See <xref linkend="chap-separate"></xref>, below, + for information about + how to build the object file in a different subdirectory.) + + </para> + + </section> + + <section> + <title>Sharing Environments (and Other Variables) Between &SConscript; Files</title> + + <para> + + In the previous example, + each of the subsidiary &SConscript; files + created its own construction environment + by calling &Environment; separately. + This obviously works fine, + but if each program must be built + with the same construction variables, + it's cumbersome and error-prone to initialize + separate construction environments + in the same way over and over in each subsidiary + &SConscript; file. + + </para> + + <para> + + &SCons; supports the ability to <emphasis>export</emphasis> variables + from a parent &SConscript; file + to its subsidiary &SConscript; files, + which allows you to share common initialized + values throughout your build hierarchy. + + </para> + + <section> + <title>Exporting Variables</title> + + <para> + + There are two ways to export a variable, + such as a construction environment, + from an &SConscript; file, + so that it may be used by other &SConscript; files. + First, you can call the &Export; + function with a list of variables, + or a string of white-space separated variable names. + Each call to &Export; adds one + or more variables to a global list + of variables that are available for import + by other &SConscript; files. + + </para> + + <sconstruct> + env = Environment() + Export('env') + </sconstruct> + + <para> + + You may export more than one variable name at a time: + + </para> + + <sconstruct> + env = Environment() + debug = ARGUMENTS['debug'] + Export('env', 'debug') + </sconstruct> + + <para> + + Because white space is not legal in Python variable names, + the &Export; function will even automatically split + a string into separate names for you: + + </para> + + <sconstruct> + Export('env debug') + </sconstruct> + + <para> + + Second, you can specify a list of + variables to export as a second argument + to the &SConscript; function call: + + </para> + + <sconstruct> + SConscript('src/SConscript', 'env') + </sconstruct> + + <para> + + Or as the &exports; keyword argument: + + </para> + + <sconstruct> + SConscript('src/SConscript', exports='env') + </sconstruct> + + <para> + + These calls export the specified variables + to only the listed &SConscript; files. + You may, however, specify more than one + &SConscript; file in a list: + + </para> + + <sconstruct> + SConscript(['src1/SConscript', + 'src2/SConscript'], exports='env') + </sconstruct> + + <para> + + This is functionally equivalent to + calling the &SConscript; function + multiple times with the same &exports; argument, + one per &SConscript; file. + + </para> + + </section> + + <section> + <title>Importing Variables</title> + + <para> + + Once a variable has been exported from a calling + &SConscript; file, + it may be used in other &SConscript; files + by calling the &Import; function: + + </para> + + <sconstruct> + Import('env') + env.Program('prog', ['prog.c']) + </sconstruct> + + <para> + + The &Import; call makes the <literal>env</literal> construction + environment available to the &SConscript; file, + after which the variable can be used to build + programs, libraries, etc. + + </para> + + <para> + + Like the &Export; function, + the &Import; function can be used + with multiple variable names: + + </para> + + <sconstruct> + Import('env', 'debug') + env = env.Clone(DEBUG = debug) + env.Program('prog', ['prog.c']) + </sconstruct> + + <para> + + And the &Import; function will similarly + split a string along white-space + into separate variable names: + + </para> + + <sconstruct> + Import('env debug') + env = env.Clone(DEBUG = debug) + env.Program('prog', ['prog.c']) + </sconstruct> + + <para> + + Lastly, as a special case, + you may import all of the variables that + have been exported by supplying an asterisk + to the &Import; function: + + </para> + + <sconstruct> + Import('*') + env = env.Clone(DEBUG = debug) + env.Program('prog', ['prog.c']) + </sconstruct> + + <para> + + If you're dealing with a lot of &SConscript; files, + this can be a lot simpler than keeping + arbitrary lists of imported variables in each file. + + </para> + + </section> + + <section> + <title>Returning Values From an &SConscript; File</title> + + <para> + + Sometimes, you would like to be able to + use information from a subsidiary + &SConscript file in some way. + For example, + suppose that you want to create one + library from source files + scattered throughout a number + of subsidiary &SConscript; files. + You can do this by using the &Return; + function to return values + from the subsidiary &SConscript; files + to the calling file. + + </para> + + <para> + + If, for example, we have two subdirectories + &foo; and &bar; + that should each contribute a source + file to a Library, + what we'd like to be able to do is + collect the object files + from the subsidiary &SConscript; calls + like this: + + </para> + + <scons_example name="Return"> + <file name="SConstruct" printme="1"> + env = Environment() + Export('env') + objs = [] + for subdir in ['foo', 'bar']: + o = SConscript('%s/SConscript' % subdir) + objs.append(o) + env.Library('prog', objs) + </file> + <directory name="foo"></directory> + <directory name="bar"></directory> + <file name="foo/SConscript"> + Import('env') + obj = env.Object('foo.c') + Return('obj') + </file> + <file name="bar/SConscript"> + Import('env') + obj = env.Object('bar.c') + Return('obj') + </file> + <file name="foo/foo.c"> + void foo(void) { printf("foo/foo.c\n"); } + </file> + <file name="bar/bar.c"> + void bar(void) { printf("bar/bar.c\n"); } + </file> + </scons_example> + + <para> + + We can do this by using the &Return; + function in the + <literal>foo/SConscript</literal> file like this: + + </para> + + <scons_example_file example="Return" name="foo/SConscript"> + </scons_example_file> + + <para> + + (The corresponding + <literal>bar/SConscript</literal> + file should be pretty obvious.) + Then when we run &SCons;, + the object files from the subsidiary subdirectories + are all correctly archived in the desired library: + + </para> + + <scons_output example="Return"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <!-- + XXX Return(stop=False) + --> + + </section> + + </section> + + <!-- + + <section> + <title>Executing From a Subdirectory: the -D, -u and -U Options</title> + + <para> + + XXX -D, -u and -U + + </para> + + </section> + + --> diff --git a/doc/user/hierarchy.xml b/doc/user/hierarchy.xml new file mode 100644 index 0000000..3495c5f --- /dev/null +++ b/doc/user/hierarchy.xml @@ -0,0 +1,746 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 Build command + +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 + +(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> + + The source code for large software projects + rarely stays in a single directory, + but is nearly always divided into a + hierarchy of directories. + Organizing a large software build using &SCons; + involves creating a hierarchy of build scripts + using the &SConscript; function. + + </para> + + <section> + <title>&SConscript; Files</title> + + <para> + + As we've already seen, + the build script at the top of the tree is called &SConstruct;. + The top-level &SConstruct; file can + use the &SConscript; function to + include other subsidiary scripts in the build. + These subsidiary scripts can, in turn, + use the &SConscript; function + to include still other scripts in the build. + By convention, these subsidiary scripts are usually + named &SConscript;. + For example, a top-level &SConstruct; file might + arrange for four subsidiary scripts to be included + in the build as follows: + + </para> + + <programlisting> + SConscript(['drivers/display/SConscript', + 'drivers/mouse/SConscript', + 'parser/SConscript', + 'utilities/SConscript']) + </programlisting> + + <para> + + In this case, the &SConstruct; file + lists all of the &SConscript; files in the build explicitly. + (Note, however, that not every directory in the tree + necessarily has an &SConscript; file.) + Alternatively, the <literal>drivers</literal> + subdirectory might contain an intermediate + &SConscript; file, + in which case the &SConscript; call in + the top-level &SConstruct; file + would look like: + + </para> + + <programlisting> + SConscript(['drivers/SConscript', + 'parser/SConscript', + 'utilities/SConscript']) + </programlisting> + + <para> + + And the subsidiary &SConscript; file in the + <literal>drivers</literal> subdirectory + would look like: + + </para> + + <programlisting> + SConscript(['display/SConscript', + 'mouse/SConscript']) + </programlisting> + + <para> + + Whether you list all of the &SConscript; files in the + top-level &SConstruct; file, + or place a subsidiary &SConscript; file in + intervening directories, + or use some mix of the two schemes, + is up to you and the needs of your software. + + </para> + + </section> + + <section> + <title>Path Names Are Relative to the &SConscript; Directory</title> + + <para> + + Subsidiary &SConscript; files make it easy to create a build + hierarchy because all of the file and directory names + in a subsidiary &SConscript; files are interpreted + relative to the directory in which the &SConscript; file lives. + Typically, this allows the &SConscript; file containing the + instructions to build a target file + to live in the same directory as the source files + from which the target will be built, + making it easy to update how the software is built + whenever files are added or deleted + (or other changes are made). + + </para> + + <para> + + For example, suppose we want to build two programs + &prog1; and &prog2; in two separate directories + with the same names as the programs. + One typical way to do this would be + with a top-level &SConstruct; file like this: + + </para> + + <programlisting> + SConscript(['prog1/SConscript', + 'prog2/SConscript']) + </programlisting> + + <para> + + And subsidiary &SConscript; files that look like this: + + </para> + + + <programlisting> + env = Environment() + env.Program('prog1', ['main.c', 'foo1.c', 'foo2.c']) + </programlisting> + + <para> + + And this: + + </para> + + + <programlisting> + env = Environment() + env.Program('prog2', ['main.c', 'bar1.c', 'bar2.c']) + </programlisting> + + <para> + + Then, when we run &SCons; in the top-level directory, + our build looks like: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o prog1/foo1.o -c prog1/foo1.c + cc -o prog1/foo2.o -c prog1/foo2.c + cc -o prog1/main.o -c prog1/main.c + cc -o prog1/prog1 prog1/main.o prog1/foo1.o prog1/foo2.o + cc -o prog2/bar1.o -c prog2/bar1.c + cc -o prog2/bar2.o -c prog2/bar2.c + cc -o prog2/main.o -c prog2/main.c + cc -o prog2/prog2 prog2/main.o prog2/bar1.o prog2/bar2.o + </screen> + + <para> + + Notice the following: + + First, you can have files with the same names + in multiple directories, like main.c in the above example. + + Second, unlike standard recursive use of &Make;, + &SCons; stays in the top-level directory + (where the &SConstruct; file lives) + and issues commands that use the path names + from the top-level directory to the + target and source files within the hierarchy. + + </para> + + </section> + + <section> + <title>Top-Level Path Names in Subsidiary &SConscript; Files</title> + + <para> + + If you need to use a file from another directory, + it's sometimes more convenient to specify + the path to a file in another directory + from the top-level &SConstruct; directory, + even when you're using that file in + a subsidiary &SConscript; file in a subdirectory. + You can tell &SCons; to interpret a path name + as relative to the top-level &SConstruct; directory, + not the local directory of the &SConscript; file, + by appending a &hash; (hash mark) + to the beginning of the path name: + + </para> + + <programlisting> + env = Environment() + env.Program('prog', ['main.c', '#lib/foo1.c', 'foo2.c']) + </programlisting> + + <para> + + In this example, + the <literal>lib</literal> directory is + directly underneath the top-level &SConstruct; directory. + If the above &SConscript; file is in a subdirectory + named <literal>src/prog</literal>, + the output would look like: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o lib/foo1.o -c lib/foo1.c + cc -o src/prog/foo2.o -c src/prog/foo2.c + cc -o src/prog/main.o -c src/prog/main.c + cc -o src/prog/prog src/prog/main.o lib/foo1.o src/prog/foo2.o + </screen> + + <para> + + (Notice that the <literal>lib/foo1.o</literal> object file + is built in the same directory as its source file. + See <xref linkend="chap-separate"></xref>, below, + for information about + how to build the object file in a different subdirectory.) + + </para> + + </section> + + <section> + <title>Absolute Path Names</title> + + <para> + + Of course, you can always specify + an absolute path name for a file--for example: + + </para> + + <programlisting> + env = Environment() + env.Program('prog', ['main.c', '/usr/joe/lib/foo1.c', 'foo2.c']) + </programlisting> + + <para> + + Which, when executed, would yield: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o src/prog/foo2.o -c src/prog/foo2.c + cc -o src/prog/main.o -c src/prog/main.c + cc -o /usr/joe/lib/foo1.o -c /usr/joe/lib/foo1.c + cc -o src/prog/prog src/prog/main.o /usr/joe/lib/foo1.o src/prog/foo2.o + </screen> + + <para> + + (As was the case with top-relative path names, + notice that the <literal>/usr/joe/lib/foo1.o</literal> object file + is built in the same directory as its source file. + See <xref linkend="chap-separate"></xref>, below, + for information about + how to build the object file in a different subdirectory.) + + </para> + + </section> + + <section> + <title>Sharing Environments (and Other Variables) Between &SConscript; Files</title> + + <para> + + In the previous example, + each of the subsidiary &SConscript; files + created its own construction environment + by calling &Environment; separately. + This obviously works fine, + but if each program must be built + with the same construction variables, + it's cumbersome and error-prone to initialize + separate construction environments + in the same way over and over in each subsidiary + &SConscript; file. + + </para> + + <para> + + &SCons; supports the ability to <emphasis>export</emphasis> variables + from a parent &SConscript; file + to its subsidiary &SConscript; files, + which allows you to share common initialized + values throughout your build hierarchy. + + </para> + + <section> + <title>Exporting Variables</title> + + <para> + + There are two ways to export a variable, + such as a construction environment, + from an &SConscript; file, + so that it may be used by other &SConscript; files. + First, you can call the &Export; + function with a list of variables, + or a string of white-space separated variable names. + Each call to &Export; adds one + or more variables to a global list + of variables that are available for import + by other &SConscript; files. + + </para> + + <programlisting> + env = Environment() + Export('env') + </programlisting> + + <para> + + You may export more than one variable name at a time: + + </para> + + <programlisting> + env = Environment() + debug = ARGUMENTS['debug'] + Export('env', 'debug') + </programlisting> + + <para> + + Because white space is not legal in Python variable names, + the &Export; function will even automatically split + a string into separate names for you: + + </para> + + <programlisting> + Export('env debug') + </programlisting> + + <para> + + Second, you can specify a list of + variables to export as a second argument + to the &SConscript; function call: + + </para> + + <programlisting> + SConscript('src/SConscript', 'env') + </programlisting> + + <para> + + Or as the &exports; keyword argument: + + </para> + + <programlisting> + SConscript('src/SConscript', exports='env') + </programlisting> + + <para> + + These calls export the specified variables + to only the listed &SConscript; files. + You may, however, specify more than one + &SConscript; file in a list: + + </para> + + <programlisting> + SConscript(['src1/SConscript', + 'src2/SConscript'], exports='env') + </programlisting> + + <para> + + This is functionally equivalent to + calling the &SConscript; function + multiple times with the same &exports; argument, + one per &SConscript; file. + + </para> + + </section> + + <section> + <title>Importing Variables</title> + + <para> + + Once a variable has been exported from a calling + &SConscript; file, + it may be used in other &SConscript; files + by calling the &Import; function: + + </para> + + <programlisting> + Import('env') + env.Program('prog', ['prog.c']) + </programlisting> + + <para> + + The &Import; call makes the <literal>env</literal> construction + environment available to the &SConscript; file, + after which the variable can be used to build + programs, libraries, etc. + + </para> + + <para> + + Like the &Export; function, + the &Import; function can be used + with multiple variable names: + + </para> + + <programlisting> + Import('env', 'debug') + env = env.Clone(DEBUG = debug) + env.Program('prog', ['prog.c']) + </programlisting> + + <para> + + And the &Import; function will similarly + split a string along white-space + into separate variable names: + + </para> + + <programlisting> + Import('env debug') + env = env.Clone(DEBUG = debug) + env.Program('prog', ['prog.c']) + </programlisting> + + <para> + + Lastly, as a special case, + you may import all of the variables that + have been exported by supplying an asterisk + to the &Import; function: + + </para> + + <programlisting> + Import('*') + env = env.Clone(DEBUG = debug) + env.Program('prog', ['prog.c']) + </programlisting> + + <para> + + If you're dealing with a lot of &SConscript; files, + this can be a lot simpler than keeping + arbitrary lists of imported variables in each file. + + </para> + + </section> + + <section> + <title>Returning Values From an &SConscript; File</title> + + <para> + + Sometimes, you would like to be able to + use information from a subsidiary + &SConscript; file in some way. + For example, + suppose that you want to create one + library from source files + scattered throughout a number + of subsidiary &SConscript; files. + You can do this by using the &Return; + function to return values + from the subsidiary &SConscript; files + to the calling file. + + </para> + + <para> + + If, for example, we have two subdirectories + &foo; and &bar; + that should each contribute a source + file to a Library, + what we'd like to be able to do is + collect the object files + from the subsidiary &SConscript; calls + like this: + + </para> + + <programlisting> + env = Environment() + Export('env') + objs = [] + for subdir in ['foo', 'bar']: + o = SConscript('%s/SConscript' % subdir) + objs.append(o) + env.Library('prog', objs) + </programlisting> + + <para> + + We can do this by using the &Return; + function in the + <literal>foo/SConscript</literal> file like this: + + </para> + + + <programlisting> + Import('env') + obj = env.Object('foo.c') + Return('obj') + </programlisting> + + <para> + + (The corresponding + <literal>bar/SConscript</literal> + file should be pretty obvious.) + Then when we run &SCons;, + the object files from the subsidiary subdirectories + are all correctly archived in the desired library: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o bar/bar.o -c bar/bar.c + cc -o foo/foo.o -c foo/foo.c + ar rc libprog.a foo/foo.o bar/bar.o + ranlib libprog.a + </screen> + + <!-- + XXX Return(stop=False) + --> + + </section> + + </section> + + <!-- + + <section> + <title>Executing From a Subdirectory: the -D, -u and -U Options</title> + + <para> + + XXX -D, -u and -U + + </para> + + </section> + + --> diff --git a/doc/user/install.in b/doc/user/install.in new file mode 100644 index 0000000..cce2de3 --- /dev/null +++ b/doc/user/install.in @@ -0,0 +1,247 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + Once a program is built, + it is often appropriate to install it in another + directory for public use. + You use the &Install; method + to arrange for a program, or any other file, + to be copied into a destination directory: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + env = Environment() + hello = env.Program('hello.c') + env.Install('__ROOT__/usr/bin', hello) + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + Note, however, that installing a file is + still considered a type of file "build." + This is important when you remember that + the default behavior of &SCons; is + to build files in or below the current directory. + If, as in the example above, + you are installing files in a directory + outside of the top-level &SConstruct; file's directory tree, + you must specify that directory + (or a higher directory, such as <literal>/</literal>) + for it to install anything there: + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q __ROOT__/usr/bin</scons_output_command> + </scons_output> + + <para> + + It can, however, be cumbersome to remember + (and type) the specific destination directory + in which the program (or any other file) + should be installed. + This is an area where the &Alias; + function comes in handy, + allowing you, for example, + to create a pseudo-target named <literal>install</literal> + that can expand to the specified destination directory: + + </para> + + <scons_example name="ex2"> + <file name="SConstruct" printme="1"> + env = Environment() + hello = env.Program('hello.c') + env.Install('__ROOT__/usr/bin', hello) + env.Alias('install', '__ROOT__/usr/bin') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + This then yields the more natural + ability to install the program + in its destination as follows: + + </para> + + <scons_output example="ex2"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q install</scons_output_command> + </scons_output> + + <section> + <title>Installing Multiple Files in a Directory</title> + + <para> + + You can install multiple files into a directory + simply by calling the &Install; function multiple times: + + </para> + + <scons_example name="ex3"> + <file name="SConstruct" printme="1"> + env = Environment() + hello = env.Program('hello.c') + goodbye = env.Program('goodbye.c') + env.Install('__ROOT__/usr/bin', hello) + env.Install('__ROOT__/usr/bin', goodbye) + env.Alias('install', '__ROOT__/usr/bin') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + <file name="goodbye.c"> + int main() { printf("Goodbye, world!\n"); } + </file> + </scons_example> + + <para> + + Or, more succinctly, listing the multiple input + files in a list + (just like you can do with any other builder): + + </para> + + <sconstruct> + env = Environment() + hello = env.Program('hello.c') + goodbye = env.Program('goodbye.c') + env.Install('__ROOT__/usr/bin', [hello, goodbye]) + env.Alias('install', '__ROOT__/usr/bin') + </sconstruct> + + <para> + + Either of these two examples yields: + + </para> + + <scons_output example="ex3"> + <scons_output_command>scons -Q install</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Installing a File Under a Different Name</title> + + <para> + + The &Install; method preserves the name + of the file when it is copied into the + destination directory. + If you need to change the name of the file + when you copy it, use the &InstallAs; function: + + </para> + + <scons_example name="ex4"> + <file name="SConstruct" printme="1"> + env = Environment() + hello = env.Program('hello.c') + env.InstallAs('__ROOT__/usr/bin/hello-new', hello) + env.Alias('install', '__ROOT__/usr/bin') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + This installs the <literal>hello</literal> + program with the name <literal>hello-new</literal> + as follows: + + </para> + + <scons_output example="ex4"> + <scons_output_command>scons -Q install</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Installing Multiple Files Under Different Names</title> + + <para> + + Lastly, if you have multiple files that all + need to be installed with different file names, + you can either call the &InstallAs; function + multiple times, or as a shorthand, + you can supply same-length lists + for both the target and source arguments: + + </para> + + <scons_example name="ex5"> + <file name="SConstruct" printme="1"> + env = Environment() + hello = env.Program('hello.c') + goodbye = env.Program('goodbye.c') + env.InstallAs(['__ROOT__/usr/bin/hello-new', + '__ROOT__/usr/bin/goodbye-new'], + [hello, goodbye]) + env.Alias('install', '__ROOT__/usr/bin') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + <file name="goodbye.c"> + int main() { printf("Goodbye, world!\n"); } + </file> + </scons_example> + + <para> + + In this case, the &InstallAs; function + loops through both lists simultaneously, + and copies each source file into its corresponding + target file name: + + </para> + + <scons_output example="ex5"> + <scons_output_command>scons -Q install</scons_output_command> + </scons_output> + + </section> diff --git a/doc/user/install.xml b/doc/user/install.xml new file mode 100644 index 0000000..e011986 --- /dev/null +++ b/doc/user/install.xml @@ -0,0 +1,237 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + Once a program is built, + it is often appropriate to install it in another + directory for public use. + You use the &Install; method + to arrange for a program, or any other file, + to be copied into a destination directory: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.Install('/usr/bin', hello) + </programlisting> + + <para> + + Note, however, that installing a file is + still considered a type of file "build." + This is important when you remember that + the default behavior of &SCons; is + to build files in or below the current directory. + If, as in the example above, + you are installing files in a directory + outside of the top-level &SConstruct; file's directory tree, + you must specify that directory + (or a higher directory, such as <literal>/</literal>) + for it to install anything there: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q /usr/bin</userinput> + Install file: "hello" as "/usr/bin/hello" + </screen> + + <para> + + It can, however, be cumbersome to remember + (and type) the specific destination directory + in which the program (or any other file) + should be installed. + This is an area where the &Alias; + function comes in handy, + allowing you, for example, + to create a pseudo-target named <literal>install</literal> + that can expand to the specified destination directory: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.Install('/usr/bin', hello) + env.Alias('install', '/usr/bin') + </programlisting> + + <para> + + This then yields the more natural + ability to install the program + in its destination as follows: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + % <userinput>scons -Q install</userinput> + Install file: "hello" as "/usr/bin/hello" + </screen> + + <section> + <title>Installing Multiple Files in a Directory</title> + + <para> + + You can install multiple files into a directory + simply by calling the &Install; function multiple times: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + goodbye = env.Program('goodbye.c') + env.Install('/usr/bin', hello) + env.Install('/usr/bin', goodbye) + env.Alias('install', '/usr/bin') + </programlisting> + + <para> + + Or, more succinctly, listing the multiple input + files in a list + (just like you can do with any other builder): + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + goodbye = env.Program('goodbye.c') + env.Install('/usr/bin', [hello, goodbye]) + env.Alias('install', '/usr/bin') + </programlisting> + + <para> + + Either of these two examples yields: + + </para> + + <screen> + % <userinput>scons -Q install</userinput> + cc -o goodbye.o -c goodbye.c + cc -o goodbye goodbye.o + Install file: "goodbye" as "/usr/bin/goodbye" + cc -o hello.o -c hello.c + cc -o hello hello.o + Install file: "hello" as "/usr/bin/hello" + </screen> + + </section> + + <section> + <title>Installing a File Under a Different Name</title> + + <para> + + The &Install; method preserves the name + of the file when it is copied into the + destination directory. + If you need to change the name of the file + when you copy it, use the &InstallAs; function: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.InstallAs('/usr/bin/hello-new', hello) + env.Alias('install', '/usr/bin') + </programlisting> + + <para> + + This installs the <literal>hello</literal> + program with the name <literal>hello-new</literal> + as follows: + + </para> + + <screen> + % <userinput>scons -Q install</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + Install file: "hello" as "/usr/bin/hello-new" + </screen> + + </section> + + <section> + <title>Installing Multiple Files Under Different Names</title> + + <para> + + Lastly, if you have multiple files that all + need to be installed with different file names, + you can either call the &InstallAs; function + multiple times, or as a shorthand, + you can supply same-length lists + for both the target and source arguments: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + goodbye = env.Program('goodbye.c') + env.InstallAs(['/usr/bin/hello-new', + '/usr/bin/goodbye-new'], + [hello, goodbye]) + env.Alias('install', '/usr/bin') + </programlisting> + + <para> + + In this case, the &InstallAs; function + loops through both lists simultaneously, + and copies each source file into its corresponding + target file name: + + </para> + + <screen> + % <userinput>scons -Q install</userinput> + cc -o goodbye.o -c goodbye.c + cc -o goodbye goodbye.o + Install file: "goodbye" as "/usr/bin/goodbye-new" + cc -o hello.o -c hello.c + cc -o hello hello.o + Install file: "hello" as "/usr/bin/hello-new" + </screen> + + </section> diff --git a/doc/user/java.in b/doc/user/java.in new file mode 100644 index 0000000..358d79b --- /dev/null +++ b/doc/user/java.in @@ -0,0 +1,657 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + So far, we've been using examples of + building C and C++ programs + to demonstrate the features of &SCons;. + &SCons; also supports building Java programs, + but Java builds are handled slightly differently, + which reflects the ways in which + the Java compiler and tools + build programs differently than + other languages' tool chains. + + </para> + + <section> + <title>Building Java Class Files: the &b-Java; Builder</title> + + <para> + + The basic activity when programming in Java, + of course, is to take one or more <filename>.java</filename> files + containing Java source code + and to call the Java compiler + to turn them into one or more + <filename>.class</filename> files. + In &SCons;, you do this + by giving the &b-link-Java; Builder + a target directory in which + to put the <filename>.class</filename> files, + and a source directory that contains + the <filename>.java</filename> files: + + </para> + + <scons_example name="java"> + <file name="SConstruct" printme="1"> + Java('classes', 'src') + </file> + <file name="src/Example1.java"> + public class Example1 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + </file> + <file name="src/Example2.java"> + public class Example2 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + </file> + <file name="src/Example3.java"> + public class Example3 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + </file> + </scons_example> + + <para> + + If the <filename>src</filename> directory contains + three <filename>.java</filename> source files, + then running &SCons; might look like this: + + </para> + + <scons_output example="java"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + &SCons; will actually search the <filename>src</filename> + directory tree for all of the <filename>.java</filename> files. + The Java compiler will then create the + necessary class files in the <filename>classes</filename> subdirectory, + based on the class names found in the <filename>.java</filename> files. + + </para> + + </section> + + <section> + <title>How &SCons; Handles Java Dependencies</title> + + <para> + + In addition to searching the source directory for + <filename>.java</filename> files, + &SCons; actually runs the <filename>.java</filename> files + through a stripped-down Java parser that figures out + what classes are defined. + In other words, &SCons; knows, + without you having to tell it, + what <filename>.class</filename> files + will be produced by the &javac; call. + So our one-liner example from the preceding section: + + </para> + + <scons_example name="java-classes"> + <file name="SConstruct" printme="1"> + Java('classes', 'src') + </file> + <file name="src/Example1.java"> + public class Example1 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + public class AdditionalClass1 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + </file> + <file name="src/Example2.java"> + public class Example2 + { + class Inner2 { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + } + </file> + <file name="src/Example3.java"> + public class Example3 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + public class AdditionalClass3 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + </file> + </scons_example> + + <para> + + Will not only tell you reliably + that the <filename>.class</filename> files + in the <filename>classes</filename> subdirectory + are up-to-date: + + </para> + + <scons_output example="java-classes"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q classes</scons_output_command> + </scons_output> + + <para> + + But it will also remove all of the generated + <filename>.class</filename> files, + even for inner classes, + without you having to specify them manually. + For example, if our + <filename>Example1.java</filename> + and + <filename>Example3.java</filename> + files both define additional classes, + and the class defined in <filename>Example2.java</filename> + has an inner class, + running <userinput>scons -c</userinput> + will clean up all of those <filename>.class</filename> files + as well: + + </para> + + <scons_output example="java-classes"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q -c classes</scons_output_command> + </scons_output> + + <para> + + To ensure correct handling of <filename>.class</filename> + dependencies in all cases, you need to tell &SCons; which Java + version is being used. This is needed because Java 1.5 changed + the <filename>.class</filename> file names for nested anonymous + inner classes. Use the <varname>JAVAVERSION</varname> construction + variable to specify the version in use. With Java 1.6, the + one-liner example can then be defined like this: + + </para> + + <sconstruct> + Java('classes', 'src', JAVAVERSION='1.6') + </sconstruct> + + <para> + See <varname>JAVAVERSION</varname> in the man page for more information. + </para> + + </section> + + <section> + <title>Building Java Archive (<filename>.jar</filename>) Files: the &b-Jar; Builder</title> + + <para> + + After building the class files, + it's common to collect them into + a Java archive (<filename>.jar</filename>) file, + which you do by calling the &b-link-Jar; Builder method. + If you want to just collect all of the + class files within a subdirectory, + you can just specify that subdirectory + as the &b-Jar; source: + + </para> + + <scons_example name="jar1"> + <file name="SConstruct" printme="1"> + Java(target = 'classes', source = 'src') + Jar(target = 'test.jar', source = 'classes') + </file> + <file name="src/Example1.java"> + public class Example1 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + </file> + <file name="src/Example2.java"> + public class Example2 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + </file> + <file name="src/Example3.java"> + public class Example3 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + </file> + </scons_example> + + <para> + + &SCons; will then pass that directory + to the &jar; command, + which will collect all of the underlying + <filename>.class</filename> files: + + </para> + + <scons_output example="jar1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + If you want to keep all of the + <filename>.class</filename> files + for multiple programs in one location, + and only archive some of them in + each <filename>.jar</filename> file, + you can pass the &b-Jar; builder a + list of files as its source. + It's extremely simple to create multiple + <filename>.jar</filename> files this way, + using the lists of target class files created + by calls to the &b-link-Java; builder + as sources to the various &b-Jar; calls: + + </para> + + <scons_example name="jar2"> + <file name="SConstruct" printme="1"> + prog1_class_files = Java(target = 'classes', source = 'prog1') + prog2_class_files = Java(target = 'classes', source = 'prog2') + Jar(target = 'prog1.jar', source = prog1_class_files) + Jar(target = 'prog2.jar', source = prog2_class_files) + </file> + <file name="prog1/Example1.java"> + public class Example1 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + </file> + <file name="prog1/Example2.java"> + public class Example2 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + </file> + <file name="prog2/Example3.java"> + public class Example3 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + </file> + <file name="prog2/Example4.java"> + public class Example4 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + </file> + </scons_example> + + <para> + + This will then create + <filename>prog1.jar</filename> + and <filename>prog2.jar</filename> + next to the subdirectories + that contain their <filename>.java</filename> files: + + </para> + + <scons_output example="jar2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Building C Header and Stub Files: the &b-JavaH; Builder</title> + + <para> + + You can generate C header and source files + for implementing native methods, + by using the &b-link-JavaH; Builder. + There are several ways of using the &JavaH Builder. + One typical invocation might look like: + + </para> + + <scons_example name="javah"> + <file name="SConstruct" printme="1"> + classes = Java(target = 'classes', source = 'src/pkg/sub') + JavaH(target = 'native', source = classes) + </file> + <file name="src/pkg/sub/Example1.java"> + package pkg.sub; + public class Example1 + { + public static void main(String[] args) + { + } + } + </file> + <file name="src/pkg/sub/Example2.java"> + package pkg.sub; + public class Example2 + { + public static void main(String[] args) + { + } + } + </file> + <file name="src/pkg/sub/Example3.java"> + package pkg.sub; + public class Example3 + { + public static void main(String[] args) + { + } + } + </file> + </scons_example> + + <para> + + The source is a list of class files generated by the + call to the &b-link-Java; Builder, + and the target is the output directory in + which we want the C header files placed. + The target + gets converted into the <option>-d</option> + when &SCons; runs &javah;: + + </para> + + <scons_output example="javah"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + In this case, + the call to &javah; + will generate the header files + <filename>native/pkg_sub_Example1.h</filename>, + <filename>native/pkg_sub_Example2.h</filename> + and + <filename>native/pkg_sub_Example3.h</filename>. + Notice that &SCons; remembered that the class + files were generated with a target directory of + <filename>classes</filename>, + and that it then specified that target directory + as the <option>-classpath</option> option + to the call to &javah;. + + </para> + + <para> + + Although it's more convenient to use + the list of class files returned by + the &b-Java; Builder + as the source of a call to the &b-JavaH; Builder, + you <emphasis>can</emphasis> + specify the list of class files + by hand, if you prefer. + If you do, + you need to set the + &cv-link-JAVACLASSDIR; construction variable + when calling &b-JavaH;: + + </para> + + <scons_example name="JAVACLASSDIR"> + <file name="SConstruct" printme="1"> + Java(target = 'classes', source = 'src/pkg/sub') + class_file_list = ['classes/pkg/sub/Example1.class', + 'classes/pkg/sub/Example2.class', + 'classes/pkg/sub/Example3.class'] + JavaH(target = 'native', source = class_file_list, JAVACLASSDIR = 'classes') + </file> + <file name="src/pkg/sub/Example1.java"> + package pkg.sub; + public class Example1 + { + public static void main(String[] args) + { + } + } + </file> + <file name="src/pkg/sub/Example2.java"> + package pkg.sub; + public class Example2 + { + public static void main(String[] args) + { + } + } + </file> + <file name="src/pkg/sub/Example3.java"> + package pkg.sub; + public class Example3 + { + public static void main(String[] args) + { + } + } + </file> + </scons_example> + + <para> + + The &cv-JAVACLASSDIR; value then + gets converted into the <option>-classpath</option> + when &SCons; runs &javah;: + + </para> + + <scons_output example="JAVACLASSDIR"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Lastly, if you don't want a separate header file + generated for each source file, + you can specify an explicit File Node + as the target of the &b-JavaH; Builder: + + </para> + + <scons_example name="javah_file"> + <file name="SConstruct" printme="1"> + classes = Java(target = 'classes', source = 'src/pkg/sub') + JavaH(target = File('native.h'), source = classes) + </file> + <file name="src/pkg/sub/Example1.java"> + package pkg.sub; + public class Example1 + { + public static void main(String[] args) + { + } + } + </file> + <file name="src/pkg/sub/Example2.java"> + package pkg.sub; + public class Example2 + { + public static void main(String[] args) + { + } + } + </file> + <file name="src/pkg/sub/Example3.java"> + package pkg.sub; + public class Example3 + { + public static void main(String[] args) + { + } + } + </file> + </scons_example> + + <para> + + Because &SCons; assumes by default + that the target of the &b-JavaH; builder is a directory, + you need to use the &File; function + to make sure that &SCons; doesn't + create a directory named <filename>native.h</filename>. + When a file is used, though, + &SCons; correctly converts the file name + into the &javah; <option>-o</option> option: + + </para> + + <scons_output example="javah_file"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Building RMI Stub and Skeleton Class Files: the &b-RMIC; Builder</title> + + <para> + + You can generate Remote Method Invocation stubs + by using the &b-link-RMIC; Builder. + The source is a list of directories, + typically returned by a call to the &b-link-Java; Builder, + and the target is an output directory + where the <filename>_Stub.class</filename> + and <filename>_Skel.class</filename> files will + be placed: + + </para> + + <scons_example name="RMIC"> + <file name="SConstruct" printme="1"> + classes = Java(target = 'classes', source = 'src/pkg/sub') + RMIC(target = 'outdir', source = classes) + </file> + <file name="src/pkg/sub/Example1.java"> + package pkg.sub; + public class Example1 + { + public static void main(String[] args) + { + } + } + </file> + <file name="src/pkg/sub/Example2.java"> + package pkg.sub; + public class Example2 + { + public static void main(String[] args) + { + } + } + </file> + </scons_example> + + <para> + + As it did with the &b-link-JavaH; Builder, + &SCons; remembers the class directory + and passes it as the <option>-classpath</option> option + to &rmic: + + </para> + + <scons_output example="RMIC"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + This example would generate the files + <filename>outdir/pkg/sub/Example1_Skel.class</filename>, + <filename>outdir/pkg/sub/Example1_Stub.class</filename>, + <filename>outdir/pkg/sub/Example2_Skel.class</filename> and + <filename>outdir/pkg/sub/Example2_Stub.class</filename>. + + </para> + + </section> diff --git a/doc/user/java.xml b/doc/user/java.xml new file mode 100644 index 0000000..8198b65 --- /dev/null +++ b/doc/user/java.xml @@ -0,0 +1,433 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + So far, we've been using examples of + building C and C++ programs + to demonstrate the features of &SCons;. + &SCons; also supports building Java programs, + but Java builds are handled slightly differently, + which reflects the ways in which + the Java compiler and tools + build programs differently than + other languages' tool chains. + + </para> + + <section> + <title>Building Java Class Files: the &b-Java; Builder</title> + + <para> + + The basic activity when programming in Java, + of course, is to take one or more <filename>.java</filename> files + containing Java source code + and to call the Java compiler + to turn them into one or more + <filename>.class</filename> files. + In &SCons;, you do this + by giving the &b-link-Java; Builder + a target directory in which + to put the <filename>.class</filename> files, + and a source directory that contains + the <filename>.java</filename> files: + + </para> + + <programlisting> + Java('classes', 'src') + </programlisting> + + <para> + + If the <filename>src</filename> directory contains + three <filename>.java</filename> source files, + then running &SCons; might look like this: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + javac -d classes -sourcepath src src/Example1.java src/Example2.java src/Example3.java + </screen> + + <para> + + &SCons; will actually search the <filename>src</filename> + directory tree for all of the <filename>.java</filename> files. + The Java compiler will then create the + necessary class files in the <filename>classes</filename> subdirectory, + based on the class names found in the <filename>.java</filename> files. + + </para> + + </section> + + <section> + <title>How &SCons; Handles Java Dependencies</title> + + <para> + + In addition to searching the source directory for + <filename>.java</filename> files, + &SCons; actually runs the <filename>.java</filename> files + through a stripped-down Java parser that figures out + what classes are defined. + In other words, &SCons; knows, + without you having to tell it, + what <filename>.class</filename> files + will be produced by the &javac; call. + So our one-liner example from the preceding section: + + </para> + + <programlisting> + Java('classes', 'src') + </programlisting> + + <para> + + Will not only tell you reliably + that the <filename>.class</filename> files + in the <filename>classes</filename> subdirectory + are up-to-date: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + javac -d classes -sourcepath src src/Example1.java src/Example2.java src/Example3.java + % <userinput>scons -Q classes</userinput> + scons: `classes' is up to date. + </screen> + + <para> + + But it will also remove all of the generated + <filename>.class</filename> files, + even for inner classes, + without you having to specify them manually. + For example, if our + <filename>Example1.java</filename> + and + <filename>Example3.java</filename> + files both define additional classes, + and the class defined in <filename>Example2.java</filename> + has an inner class, + running <userinput>scons -c</userinput> + will clean up all of those <filename>.class</filename> files + as well: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + javac -d classes -sourcepath src src/Example1.java src/Example2.java src/Example3.java + % <userinput>scons -Q -c classes</userinput> + Removed classes/Example1.class + Removed classes/AdditionalClass1.class + Removed classes/Example2$Inner2.class + Removed classes/Example2.class + Removed classes/Example3.class + Removed classes/AdditionalClass3.class + </screen> + + <para> + + To ensure correct handling of <filename>.class</filename> + dependencies in all cases, you need to tell &SCons; which Java + version is being used. This is needed because Java 1.5 changed + the <filename>.class</filename> file names for nested anonymous + inner classes. Use the <varname>JAVAVERSION</varname> construction + variable to specify the version in use. With Java 1.6, the + one-liner example can then be defined like this: + + </para> + + <programlisting> + Java('classes', 'src', JAVAVERSION='1.6') + </programlisting> + + <para> + See <varname>JAVAVERSION</varname> in the man page for more information. + </para> + + </section> + + <section> + <title>Building Java Archive (<filename>.jar</filename>) Files: the &b-Jar; Builder</title> + + <para> + + After building the class files, + it's common to collect them into + a Java archive (<filename>.jar</filename>) file, + which you do by calling the &b-link-Jar; Builder method. + If you want to just collect all of the + class files within a subdirectory, + you can just specify that subdirectory + as the &b-Jar; source: + + </para> + + <programlisting> + Java(target = 'classes', source = 'src') + Jar(target = 'test.jar', source = 'classes') + </programlisting> + + <para> + + &SCons; will then pass that directory + to the &jar; command, + which will collect all of the underlying + <filename>.class</filename> files: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + javac -d classes -sourcepath src src/Example1.java src/Example2.java src/Example3.java + jar cf test.jar classes + </screen> + + <para> + + If you want to keep all of the + <filename>.class</filename> files + for multiple programs in one location, + and only archive some of them in + each <filename>.jar</filename> file, + you can pass the &b-Jar; builder a + list of files as its source. + It's extremely simple to create multiple + <filename>.jar</filename> files this way, + using the lists of target class files created + by calls to the &b-link-Java; builder + as sources to the various &b-Jar; calls: + + </para> + + <programlisting> + prog1_class_files = Java(target = 'classes', source = 'prog1') + prog2_class_files = Java(target = 'classes', source = 'prog2') + Jar(target = 'prog1.jar', source = prog1_class_files) + Jar(target = 'prog2.jar', source = prog2_class_files) + </programlisting> + + <para> + + This will then create + <filename>prog1.jar</filename> + and <filename>prog2.jar</filename> + next to the subdirectories + that contain their <filename>.java</filename> files: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + javac -d classes -sourcepath prog1 prog1/Example1.java prog1/Example2.java + javac -d classes -sourcepath prog2 prog2/Example3.java prog2/Example4.java + jar cf prog1.jar -C classes Example1.class -C classes Example2.class + jar cf prog2.jar -C classes Example3.class -C classes Example4.class + </screen> + + </section> + + <section> + <title>Building C Header and Stub Files: the &b-JavaH; Builder</title> + + <para> + + You can generate C header and source files + for implementing native methods, + by using the &b-link-JavaH; Builder. + There are several ways of using the &JavaH; Builder. + One typical invocation might look like: + + </para> + + <programlisting> + classes = Java(target = 'classes', source = 'src/pkg/sub') + JavaH(target = 'native', source = classes) + </programlisting> + + <para> + + The source is a list of class files generated by the + call to the &b-link-Java; Builder, + and the target is the output directory in + which we want the C header files placed. + The target + gets converted into the <option>-d</option> + when &SCons; runs &javah;: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + javac -d classes -sourcepath src/pkg/sub src/pkg/sub/Example1.java src/pkg/sub/Example2.java src/pkg/sub/Example3.java + javah -d native -classpath classes pkg.sub.Example1 pkg.sub.Example2 pkg.sub.Example3 + </screen> + + <para> + + In this case, + the call to &javah; + will generate the header files + <filename>native/pkg_sub_Example1.h</filename>, + <filename>native/pkg_sub_Example2.h</filename> + and + <filename>native/pkg_sub_Example3.h</filename>. + Notice that &SCons; remembered that the class + files were generated with a target directory of + <filename>classes</filename>, + and that it then specified that target directory + as the <option>-classpath</option> option + to the call to &javah;. + + </para> + + <para> + + Although it's more convenient to use + the list of class files returned by + the &b-Java; Builder + as the source of a call to the &b-JavaH; Builder, + you <emphasis>can</emphasis> + specify the list of class files + by hand, if you prefer. + If you do, + you need to set the + &cv-link-JAVACLASSDIR; construction variable + when calling &b-JavaH;: + + </para> + + <programlisting> + Java(target = 'classes', source = 'src/pkg/sub') + class_file_list = ['classes/pkg/sub/Example1.class', + 'classes/pkg/sub/Example2.class', + 'classes/pkg/sub/Example3.class'] + JavaH(target = 'native', source = class_file_list, JAVACLASSDIR = 'classes') + </programlisting> + + <para> + + The &cv-JAVACLASSDIR; value then + gets converted into the <option>-classpath</option> + when &SCons; runs &javah;: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + javac -d classes -sourcepath src/pkg/sub src/pkg/sub/Example1.java src/pkg/sub/Example2.java src/pkg/sub/Example3.java + javah -d native -classpath classes pkg.sub.Example1 pkg.sub.Example2 pkg.sub.Example3 + </screen> + + <para> + + Lastly, if you don't want a separate header file + generated for each source file, + you can specify an explicit File Node + as the target of the &b-JavaH; Builder: + + </para> + + <programlisting> + classes = Java(target = 'classes', source = 'src/pkg/sub') + JavaH(target = File('native.h'), source = classes) + </programlisting> + + <para> + + Because &SCons; assumes by default + that the target of the &b-JavaH; builder is a directory, + you need to use the &File; function + to make sure that &SCons; doesn't + create a directory named <filename>native.h</filename>. + When a file is used, though, + &SCons; correctly converts the file name + into the &javah; <option>-o</option> option: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + javac -d classes -sourcepath src/pkg/sub src/pkg/sub/Example1.java src/pkg/sub/Example2.java src/pkg/sub/Example3.java + javah -o native.h -classpath classes pkg.sub.Example1 pkg.sub.Example2 pkg.sub.Example3 + </screen> + + </section> + + <section> + <title>Building RMI Stub and Skeleton Class Files: the &b-RMIC; Builder</title> + + <para> + + You can generate Remote Method Invocation stubs + by using the &b-link-RMIC; Builder. + The source is a list of directories, + typically returned by a call to the &b-link-Java; Builder, + and the target is an output directory + where the <filename>_Stub.class</filename> + and <filename>_Skel.class</filename> files will + be placed: + + </para> + + <programlisting> + classes = Java(target = 'classes', source = 'src/pkg/sub') + RMIC(target = 'outdir', source = classes) + </programlisting> + + <para> + + As it did with the &b-link-JavaH; Builder, + &SCons; remembers the class directory + and passes it as the <option>-classpath</option> option + to &rmic;: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + javac -d classes -sourcepath src/pkg/sub src/pkg/sub/Example1.java src/pkg/sub/Example2.java + rmic -d outdir -classpath classes pkg.sub.Example1 pkg.sub.Example2 + </screen> + + <para> + + This example would generate the files + <filename>outdir/pkg/sub/Example1_Skel.class</filename>, + <filename>outdir/pkg/sub/Example1_Stub.class</filename>, + <filename>outdir/pkg/sub/Example2_Skel.class</filename> and + <filename>outdir/pkg/sub/Example2_Stub.class</filename>. + + </para> + + </section> diff --git a/doc/user/less-simple.in b/doc/user/less-simple.in new file mode 100644 index 0000000..e19ba13 --- /dev/null +++ b/doc/user/less-simple.in @@ -0,0 +1,623 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + In this chapter, + you will see several examples of + very simple build configurations using &SCons;, + which will demonstrate how easy + it is to use &SCons; to + build programs from several different programming languages + on different types of systems. + + </para> + + <section> + <title>Specifying the Name of the Target (Output) File</title> + + <para> + + You've seen that when you call the &b-link-Program; builder method, + it builds the resulting program with the same + base name as the source file. + That is, the following call to build an + executable program from the &hello_c; source file + will build an executable program named &hello; on POSIX systems, + and an executable program named &hello_exe; on Windows systems: + + </para> + + <programlisting> + Program('hello.c') + </programlisting> + + <para> + + If you want to build a program with + a different name than the base of the source file name, + you simply put the target file name + to the left of the source file name: + + </para> + + <scons_example name="target"> + <file name="SConstruct" printme="1"> + Program('new_hello', 'hello.c') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + (&SCons; requires the target file name first, + followed by the source file name, + so that the order mimics that of an + assignment statement in most programming languages, + including Python: + <literal>"program = source files"</literal>.) + + </para> + + <para> + + Now &SCons; will build an executable program + named &new_hello; when run on a POSIX system: + + </para> + + <scons_output example="target" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + And &SCons; will build an executable program + named &new_hello_exe; when run on a Windows system: + + </para> + + <scons_output example="target" os="win32"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Compiling Multiple Source Files</title> + + <para> + + You've just seen how to configure &SCons; + to compile a program from a single source file. + It's more common, of course, + that you'll need to build a program from + many input source files, not just one. + To do this, you need to put the + source files in a Python list + (enclosed in square brackets), + like so: + + </para> + + <scons_example name="ex2"> + <file name="SConstruct" printme="1"> + Program(['prog.c', 'file1.c', 'file2.c']) + </file> + <file name="prog.c"> + int main() { printf("prog.c\n"); } + </file> + <file name="file1.c"> + void file1() { printf("file1.c\n"); } + </file> + <file name="file2.c"> + void file2() { printf("file2.c\n"); } + </file> + </scons_example> + + <para> + + A build of the above example would look like: + + </para> + + <scons_output example="ex2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Notice that &SCons; + deduces the output program name + from the first source file specified + in the list--that is, + because the first source file was &prog_c;, + &SCons; will name the resulting program &prog; + (or &prog_exe; on a Windows system). + If you want to specify a different program name, + then (as we've seen in the previous section) + you slide the list of source files + over to the right + to make room for the output program file name. + (&SCons; puts the output file name to the left + of the source file names + so that the order mimics that of an + assignment statement: "program = source files".) + This makes our example: + + </para> + + <scons_example name="ex3"> + <file name="SConstruct" printme="1"> + Program('program', ['prog.c', 'file1.c', 'file2.c']) + </file> + <file name="prog.c"> + int main() { printf("prog.c\n"); } + </file> + <file name="file1.c"> + void file1() { printf("file1.c\n"); } + </file> + <file name="file2.c"> + void file2() { printf("file2.c\n"); } + </file> + </scons_example> + + <para> + + On Linux, a build of this example would look like: + + </para> + + <scons_output example="ex3" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Or on Windows: + + </para> + + <scons_output example="ex3" os="win32"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Making a list of files with &Glob;</title> + + <para> + + You can also use the &Glob; function to find all files matching a + certain template, using the standard shell pattern matching + characters <literal>*</literal>, <literal>?</literal> + and <literal>[abc]</literal> to match any of + <literal>a</literal>, <literal>b</literal> or <literal>c</literal>. + <literal>[!abc]</literal> is also supported, + to match any character <emphasis>except</emphasis> + <literal>a</literal>, <literal>b</literal> or <literal>c</literal>. + This makes many multi-source-file builds quite easy: + + </para> + + <sconstruct> + Program('program', Glob('*.c')) + </sconstruct> + + <para> + + The SCons man page has more details on using &Glob; + with variant directories + (see <xref linkend="chap-variants"></xref>, below) + and repositories + (see <xref linkend="chap-repositories"></xref>, below), + and returning strings rather than Nodes. + + </para> + + </section> + + <section> + <title>Specifying Single Files Vs. Lists of Files</title> + + <para> + + We've now shown you two ways to specify + the source for a program, + one with a list of files: + + </para> + + <sconstruct> + Program('hello', ['file1.c', 'file2.c']) + </sconstruct> + + <para> + + And one with a single file: + + </para> + + <sconstruct> + Program('hello', 'hello.c') + </sconstruct> + + <para> + + You could actually put a single file name in a list, too, + which you might prefer just for the sake of consistency: + + </para> + + <sconstruct> + Program('hello', ['hello.c']) + </sconstruct> + + <para> + + &SCons; functions will accept a single file name in either form. + In fact, internally, &SCons; treats all input as lists of files, + but allows you to omit the square brackets + to cut down a little on the typing + when there's only a single file name. + + </para> + + <important> + + <para> + + Although &SCons; functions + are forgiving about whether or not you + use a string vs. a list for a single file name, + Python itself is more strict about + treating lists and strings differently. + So where &SCons; allows either + a string or list: + + </para> + + <sconstruct> + # The following two calls both work correctly: + Program('program1', 'program1.c') + Program('program2', ['program2.c']) + </sconstruct> + + <para> + + Trying to do "Python things" that mix strings and + lists will cause errors or lead to incorrect results: + + </para> + + <sconstruct> + common_sources = ['file1.c', 'file2.c'] + + # THE FOLLOWING IS INCORRECT AND GENERATES A PYTHON ERROR + # BECAUSE IT TRIES TO ADD A STRING TO A LIST: + Program('program1', common_sources + 'program1.c') + + # The following works correctly, because it's adding two + # lists together to make another list. + Program('program2', common_sources + ['program2.c']) + </sconstruct> + + </important> + + </section> + + <section> + <title>Making Lists of Files Easier to Read</title> + + <para> + + One drawback to the use of a Python list + for source files is that + each file name must be enclosed in quotes + (either single quotes or double quotes). + This can get cumbersome and difficult to read + when the list of file names is long. + Fortunately, &SCons; and Python provide a number of ways + to make sure that + the &SConstruct; file stays easy to read. + + </para> + + <para> + + To make long lists of file names + easier to deal with, &SCons; provides a + &Split; function + that takes a quoted list of file names, + with the names separated by spaces or other white-space characters, + and turns it into a list of separate file names. + Using the &Split; function turns the + previous example into: + + </para> + + <programlisting> + Program('program', Split('main.c file1.c file2.c')) + </programlisting> + + <para> + + (If you're already familiar with Python, + you'll have realized that this is similar to the + <function>split()</function> method + in the Python standard <function>string</function> module. + Unlike the <function>string.split()</function> method, + however, the &Split; function + does not require a string as input + and will wrap up a single non-string object in a list, + or return its argument untouched if it's already a list. + This comes in handy as a way to make sure + arbitrary values can be passed to &SCons; functions + without having to check the type of the variable by hand.) + + </para> + + <para> + + Putting the call to the &Split; function + inside the &b-Program; call + can also be a little unwieldy. + A more readable alternative is to + assign the output from the &Split; call + to a variable name, + and then use the variable when calling the + &b-Program; function: + + </para> + + <programlisting> + src_files = Split('main.c file1.c file2.c') + Program('program', src_files) + </programlisting> + + <para> + + Lastly, the &Split; function + doesn't care how much white space separates + the file names in the quoted string. + This allows you to create lists of file + names that span multiple lines, + which often makes for easier editing: + + </para> + + <programlisting> + src_files = Split("""main.c + file1.c + file2.c""") + Program('program', src_files) + </programlisting> + + <para> + + (Note in this example that we used + the Python "triple-quote" syntax, + which allows a string to contain + multiple lines. + The three quotes can be either + single or double quotes.) + + </para> + + </section> + + <section> + <title>Keyword Arguments</title> + + <para> + + &SCons; also allows you to identify + the output file and input source files + using Python keyword arguments. + The output file is known as the + <emphasis>target</emphasis>, + and the source file(s) are known (logically enough) as the + <emphasis>source</emphasis>. + The Python syntax for this is: + + </para> + + <programlisting> + src_files = Split('main.c file1.c file2.c') + Program(target = 'program', source = src_files) + </programlisting> + + <para> + + Because the keywords explicitly identify + what each argument is, + you can actually reverse the order if you prefer: + + </para> + + <programlisting> + src_files = Split('main.c file1.c file2.c') + Program(source = src_files, target = 'program') + </programlisting> + + <para> + + Whether or not you choose to use keyword arguments + to identify the target and source files, + and the order in which you specify them + when using keywords, + are purely personal choices; + &SCons; functions the same regardless. + + </para> + + </section> + + <section> + <title>Compiling Multiple Programs</title> + + <para> + + In order to compile multiple programs + within the same &SConstruct; file, + simply call the &Program; method + multiple times, + once for each program you need to build: + + </para> + + <scons_example name="ex4"> + <file name="SConstruct" printme="1"> + Program('foo.c') + Program('bar', ['bar1.c', 'bar2.c']) + </file> + <file name="foo.c"> + int main() { printf("foo.c\n"); } + </file> + <file name="bar1.c"> + int main() { printf("bar1.c\n"); } + </file> + <file name="bar2.c"> + void bar2() { printf("bar2.c\n"); } + </file> + </scons_example> + + <para> + + &SCons; would then build the programs as follows: + + </para> + + <scons_output example="ex4"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Notice that &SCons; does not necessarily build the + programs in the same order in which you specify + them in the &SConstruct; file. + &SCons; does, however, recognize that + the individual object files must be built + before the resulting program can be built. + We'll discuss this in greater detail in + the "Dependencies" section, below. + + </para> + + </section> + + <section> + <title>Sharing Source Files Between Multiple Programs</title> + + <para> + + It's common to re-use code by sharing source files + between multiple programs. + One way to do this is to create a library + from the common source files, + which can then be linked into resulting programs. + (Creating libraries is discussed in + <xref linkend="chap-libraries"></xref>, below.) + + </para> + + <para> + + A more straightforward, but perhaps less convenient, + way to share source files between multiple programs + is simply to include the common files + in the lists of source files for each program: + + </para> + + <scons_example name="ex5"> + <file name="SConstruct" printme="1"> + Program(Split('foo.c common1.c common2.c')) + Program('bar', Split('bar1.c bar2.c common1.c common2.c')) + </file> + <file name="foo.c"> + int main() { printf("foo.c\n"); } + </file> + <file name="bar1.c"> + int main() { printf("bar1.c\n"); } + </file> + <file name="bar2.c"> + int bar2() { printf("bar2.c\n"); } + </file> + <file name="common1.c"> + void common1() { printf("common1.c\n"); } + </file> + <file name="common2.c"> + void common22() { printf("common2.c\n"); } + </file> + </scons_example> + + <para> + + &SCons; recognizes that the object files for + the &common1_c; and &common2_c; source files + each need to be built only once, + even though the resulting object files are + each linked in to both of the resulting executable programs: + + </para> + + <scons_output example="ex5"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + If two or more programs + share a lot of common source files, + repeating the common files in the list for each program + can be a maintenance problem when you need to change the + list of common files. + You can simplify this by creating a separate Python list + to hold the common file names, + and concatenating it with other lists + using the Python + operator: + + </para> + + <programlisting> + common = ['common1.c', 'common2.c'] + foo_files = ['foo.c'] + common + bar_files = ['bar1.c', 'bar2.c'] + common + Program('foo', foo_files) + Program('bar', bar_files) + </programlisting> + + <para> + + This is functionally equivalent to the previous example. + + </para> + + </section> diff --git a/doc/user/less-simple.xml b/doc/user/less-simple.xml new file mode 100644 index 0000000..57c61e2 --- /dev/null +++ b/doc/user/less-simple.xml @@ -0,0 +1,608 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + In this chapter, + you will see several examples of + very simple build configurations using &SCons;, + which will demonstrate how easy + it is to use &SCons; to + build programs from several different programming languages + on different types of systems. + + </para> + + <section> + <title>Specifying the Name of the Target (Output) File</title> + + <para> + + You've seen that when you call the &b-link-Program; builder method, + it builds the resulting program with the same + base name as the source file. + That is, the following call to build an + executable program from the &hello_c; source file + will build an executable program named &hello; on POSIX systems, + and an executable program named &hello_exe; on Windows systems: + + </para> + + <programlisting> + Program('hello.c') + </programlisting> + + <para> + + If you want to build a program with + a different name than the base of the source file name, + you simply put the target file name + to the left of the source file name: + + </para> + + <programlisting> + Program('new_hello', 'hello.c') + </programlisting> + + <para> + + (&SCons; requires the target file name first, + followed by the source file name, + so that the order mimics that of an + assignment statement in most programming languages, + including Python: + <literal>"program = source files"</literal>.) + + </para> + + <para> + + Now &SCons; will build an executable program + named &new_hello; when run on a POSIX system: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o new_hello hello.o + </screen> + + <para> + + And &SCons; will build an executable program + named &new_hello_exe; when run on a Windows system: + + </para> + + <screen> + C:\><userinput>scons -Q</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + cl /Fohello.obj /c hello.c /nologo + link /nologo /OUT:new_hello.exe hello.obj + </screen> + + </section> + + <section> + <title>Compiling Multiple Source Files</title> + + <para> + + You've just seen how to configure &SCons; + to compile a program from a single source file. + It's more common, of course, + that you'll need to build a program from + many input source files, not just one. + To do this, you need to put the + source files in a Python list + (enclosed in square brackets), + like so: + + </para> + + <programlisting> + Program(['prog.c', 'file1.c', 'file2.c']) + </programlisting> + + <para> + + A build of the above example would look like: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o file1.o -c file1.c + cc -o file2.o -c file2.c + cc -o prog.o -c prog.c + cc -o prog prog.o file1.o file2.o + </screen> + + <para> + + Notice that &SCons; + deduces the output program name + from the first source file specified + in the list--that is, + because the first source file was &prog_c;, + &SCons; will name the resulting program &prog; + (or &prog_exe; on a Windows system). + If you want to specify a different program name, + then (as we've seen in the previous section) + you slide the list of source files + over to the right + to make room for the output program file name. + (&SCons; puts the output file name to the left + of the source file names + so that the order mimics that of an + assignment statement: "program = source files".) + This makes our example: + + </para> + + <programlisting> + Program('program', ['prog.c', 'file1.c', 'file2.c']) + </programlisting> + + <para> + + On Linux, a build of this example would look like: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o file1.o -c file1.c + cc -o file2.o -c file2.c + cc -o prog.o -c prog.c + cc -o program prog.o file1.o file2.o + </screen> + + <para> + + Or on Windows: + + </para> + + <screen> + C:\><userinput>scons -Q</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + cl /Fofile1.obj /c file1.c /nologo + cl /Fofile2.obj /c file2.c /nologo + cl /Foprog.obj /c prog.c /nologo + link /nologo /OUT:program.exe prog.obj file1.obj file2.obj + </screen> + + </section> + + <section> + <title>Making a list of files with &Glob;</title> + + <para> + + You can also use the &Glob; function to find all files matching a + certain template, using the standard shell pattern matching + characters <literal>*</literal>, <literal>?</literal> + and <literal>[abc]</literal> to match any of + <literal>a</literal>, <literal>b</literal> or <literal>c</literal>. + <literal>[!abc]</literal> is also supported, + to match any character <emphasis>except</emphasis> + <literal>a</literal>, <literal>b</literal> or <literal>c</literal>. + This makes many multi-source-file builds quite easy: + + </para> + + <programlisting> + Program('program', Glob('*.c')) + </programlisting> + + <para> + + The SCons man page has more details on using &Glob; + with variant directories + (see <xref linkend="chap-variants"></xref>, below) + and repositories + (see <xref linkend="chap-repositories"></xref>, below), + and returning strings rather than Nodes. + + </para> + + </section> + + <section> + <title>Specifying Single Files Vs. Lists of Files</title> + + <para> + + We've now shown you two ways to specify + the source for a program, + one with a list of files: + + </para> + + <programlisting> + Program('hello', ['file1.c', 'file2.c']) + </programlisting> + + <para> + + And one with a single file: + + </para> + + <programlisting> + Program('hello', 'hello.c') + </programlisting> + + <para> + + You could actually put a single file name in a list, too, + which you might prefer just for the sake of consistency: + + </para> + + <programlisting> + Program('hello', ['hello.c']) + </programlisting> + + <para> + + &SCons; functions will accept a single file name in either form. + In fact, internally, &SCons; treats all input as lists of files, + but allows you to omit the square brackets + to cut down a little on the typing + when there's only a single file name. + + </para> + + <important> + + <para> + + Although &SCons; functions + are forgiving about whether or not you + use a string vs. a list for a single file name, + Python itself is more strict about + treating lists and strings differently. + So where &SCons; allows either + a string or list: + + </para> + + <programlisting> + # The following two calls both work correctly: + Program('program1', 'program1.c') + Program('program2', ['program2.c']) + </programlisting> + + <para> + + Trying to do "Python things" that mix strings and + lists will cause errors or lead to incorrect results: + + </para> + + <programlisting> + common_sources = ['file1.c', 'file2.c'] + + # THE FOLLOWING IS INCORRECT AND GENERATES A PYTHON ERROR + # BECAUSE IT TRIES TO ADD A STRING TO A LIST: + Program('program1', common_sources + 'program1.c') + + # The following works correctly, because it's adding two + # lists together to make another list. + Program('program2', common_sources + ['program2.c']) + </programlisting> + + </important> + + </section> + + <section> + <title>Making Lists of Files Easier to Read</title> + + <para> + + One drawback to the use of a Python list + for source files is that + each file name must be enclosed in quotes + (either single quotes or double quotes). + This can get cumbersome and difficult to read + when the list of file names is long. + Fortunately, &SCons; and Python provide a number of ways + to make sure that + the &SConstruct; file stays easy to read. + + </para> + + <para> + + To make long lists of file names + easier to deal with, &SCons; provides a + &Split; function + that takes a quoted list of file names, + with the names separated by spaces or other white-space characters, + and turns it into a list of separate file names. + Using the &Split; function turns the + previous example into: + + </para> + + <programlisting> + Program('program', Split('main.c file1.c file2.c')) + </programlisting> + + <para> + + (If you're already familiar with Python, + you'll have realized that this is similar to the + <function>split()</function> method + in the Python standard <function>string</function> module. + Unlike the <function>string.split()</function> method, + however, the &Split; function + does not require a string as input + and will wrap up a single non-string object in a list, + or return its argument untouched if it's already a list. + This comes in handy as a way to make sure + arbitrary values can be passed to &SCons; functions + without having to check the type of the variable by hand.) + + </para> + + <para> + + Putting the call to the &Split; function + inside the &b-Program; call + can also be a little unwieldy. + A more readable alternative is to + assign the output from the &Split; call + to a variable name, + and then use the variable when calling the + &b-Program; function: + + </para> + + <programlisting> + src_files = Split('main.c file1.c file2.c') + Program('program', src_files) + </programlisting> + + <para> + + Lastly, the &Split; function + doesn't care how much white space separates + the file names in the quoted string. + This allows you to create lists of file + names that span multiple lines, + which often makes for easier editing: + + </para> + + <programlisting> + src_files = Split("""main.c + file1.c + file2.c""") + Program('program', src_files) + </programlisting> + + <para> + + (Note in this example that we used + the Python "triple-quote" syntax, + which allows a string to contain + multiple lines. + The three quotes can be either + single or double quotes.) + + </para> + + </section> + + <section> + <title>Keyword Arguments</title> + + <para> + + &SCons; also allows you to identify + the output file and input source files + using Python keyword arguments. + The output file is known as the + <emphasis>target</emphasis>, + and the source file(s) are known (logically enough) as the + <emphasis>source</emphasis>. + The Python syntax for this is: + + </para> + + <programlisting> + src_files = Split('main.c file1.c file2.c') + Program(target = 'program', source = src_files) + </programlisting> + + <para> + + Because the keywords explicitly identify + what each argument is, + you can actually reverse the order if you prefer: + + </para> + + <programlisting> + src_files = Split('main.c file1.c file2.c') + Program(source = src_files, target = 'program') + </programlisting> + + <para> + + Whether or not you choose to use keyword arguments + to identify the target and source files, + and the order in which you specify them + when using keywords, + are purely personal choices; + &SCons; functions the same regardless. + + </para> + + </section> + + <section> + <title>Compiling Multiple Programs</title> + + <para> + + In order to compile multiple programs + within the same &SConstruct; file, + simply call the &Program; method + multiple times, + once for each program you need to build: + + </para> + + <programlisting> + Program('foo.c') + Program('bar', ['bar1.c', 'bar2.c']) + </programlisting> + + <para> + + &SCons; would then build the programs as follows: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o bar1.o -c bar1.c + cc -o bar2.o -c bar2.c + cc -o bar bar1.o bar2.o + cc -o foo.o -c foo.c + cc -o foo foo.o + </screen> + + <para> + + Notice that &SCons; does not necessarily build the + programs in the same order in which you specify + them in the &SConstruct; file. + &SCons; does, however, recognize that + the individual object files must be built + before the resulting program can be built. + We'll discuss this in greater detail in + the "Dependencies" section, below. + + </para> + + </section> + + <section> + <title>Sharing Source Files Between Multiple Programs</title> + + <para> + + It's common to re-use code by sharing source files + between multiple programs. + One way to do this is to create a library + from the common source files, + which can then be linked into resulting programs. + (Creating libraries is discussed in + <xref linkend="chap-libraries"></xref>, below.) + + </para> + + <para> + + A more straightforward, but perhaps less convenient, + way to share source files between multiple programs + is simply to include the common files + in the lists of source files for each program: + + </para> + + <programlisting> + Program(Split('foo.c common1.c common2.c')) + Program('bar', Split('bar1.c bar2.c common1.c common2.c')) + </programlisting> + + <para> + + &SCons; recognizes that the object files for + the &common1_c; and &common2_c; source files + each need to be built only once, + even though the resulting object files are + each linked in to both of the resulting executable programs: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o bar1.o -c bar1.c + cc -o bar2.o -c bar2.c + cc -o common1.o -c common1.c + cc -o common2.o -c common2.c + cc -o bar bar1.o bar2.o common1.o common2.o + cc -o foo.o -c foo.c + cc -o foo foo.o common1.o common2.o + </screen> + + <para> + + If two or more programs + share a lot of common source files, + repeating the common files in the list for each program + can be a maintenance problem when you need to change the + list of common files. + You can simplify this by creating a separate Python list + to hold the common file names, + and concatenating it with other lists + using the Python + operator: + + </para> + + <programlisting> + common = ['common1.c', 'common2.c'] + foo_files = ['foo.c'] + common + bar_files = ['bar1.c', 'bar2.c'] + common + Program('foo', foo_files) + Program('bar', bar_files) + </programlisting> + + <para> + + This is functionally equivalent to the previous example. + + </para> + + </section> diff --git a/doc/user/libraries.in b/doc/user/libraries.in new file mode 100644 index 0000000..4cce091 --- /dev/null +++ b/doc/user/libraries.in @@ -0,0 +1,445 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + It's often useful to organize large software projects + by collecting parts of the software into one or more libraries. + &SCons; makes it easy to create libraries + and to use them in the programs. + + </para> + + <section> + <title>Building Libraries</title> + + <para> + + You build your own libraries by specifying &b-link-Library; + instead of &b-link-Program;: + + </para> + + <scons_example name="ex1" printme="1"> + <file name="SConstruct" printme="1"> + Library('foo', ['f1.c', 'f2.c', 'f3.c']) + </file> + <file name="f1.c"> + void f1() { printf("f1.c\n"); } + </file> + <file name="f2.c"> + void f2() { printf("f2.c\n"); } + </file> + <file name="f3.c"> + void f3() { printf("f3.c\n"); } + </file> + </scons_example> + + <para> + + &SCons; uses the appropriate library prefix and suffix for your system. + So on POSIX or Linux systems, + the above example would build as follows + (although &ranlib; may not be called on all systems): + + </para> + + <scons_output example="ex1" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + On a Windows system, + a build of the above example would look like: + + </para> + + <scons_output example="ex1" os="win32"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + The rules for the target name of the library + are similar to those for programs: + if you don't explicitly specify a target library name, + &SCons; will deduce one from the + name of the first source file specified, + and &SCons; will add an appropriate + file prefix and suffix if you leave them off. + + </para> + + <section> + <title>Building Libraries From Source Code or Object Files</title> + + <para> + + The previous example shows building a library from a + list of source files. + You can, however, also give the &b-link-Library; call + object files, + and it will correctly realize + In fact, you can arbitrarily mix source code files + and object files in the source list: + + </para> + + <scons_example name="objects" printme="1"> + <file name="SConstruct" printme="1"> + Library('foo', ['f1.c', 'f2.o', 'f3.c', 'f4.o']) + </file> + <file name="f1.c"> + void f1() { printf("f1.c\n"); } + </file> + <file name="f2.o"> + object file + </file> + <file name="f3.c"> + void f3() { printf("f3.c\n"); } + </file> + <file name="f4.o"> + object file + </file> + </scons_example> + + <para> + + And SCons realizes that only the source code files + must be compiled into object files + before creating the final library: + + </para> + + <scons_output example="objects" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Of course, in this example, the object files + must already exist for the build to succeed. + See <xref linkend="chap-nodes"></xref>, below, + for information about how you can + build object files explicitly + and include the built files in a library. + + </para> + + </section> + + <section> + <title>Building Static Libraries Explicitly: the &b-StaticLibrary; Builder</title> + + <para> + + The &b-link-Library; function builds a traditional static library. + If you want to be explicit about the type of library being built, + you can use the synonym &b-link-StaticLibrary; function + instead of &b-Library;: + + </para> + + <scons_example name="StaticLibrary" printme="1"> + <file name="SConstruct" printme="1"> + StaticLibrary('foo', ['f1.c', 'f2.c', 'f3.c']) + </file> + </scons_example> + + <para> + + There is no functional difference between the + &b-link-StaticLibrary; and &b-Library; functions. + + </para> + + </section> + + <section> + <title>Building Shared (DLL) Libraries: the &b-SharedLibrary; Builder</title> + + <para> + + If you want to build a shared library (on POSIX systems) + or a DLL file (on Windows systems), + you use the &b-link-SharedLibrary; function: + + </para> + + <scons_example name="SharedLibrary" printme="1"> + <file name="SConstruct" printme="1"> + SharedLibrary('foo', ['f1.c', 'f2.c', 'f3.c']) + </file> + <file name="f1.c"> + void f1() { printf("f1.c\n"); } + </file> + <file name="f2.c"> + void f2() { printf("f2.c\n"); } + </file> + <file name="f3.c"> + void f3() { printf("f3.c\n"); } + </file> + </scons_example> + + <para> + + The output on POSIX: + + </para> + + <scons_output example="SharedLibrary" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + And the output on Windows: + + </para> + + <scons_output example="SharedLibrary" os="win32"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Notice again that &SCons; takes care of + building the output file correctly, + adding the <literal>-shared</literal> option + for a POSIX compilation, + and the <literal>/dll</literal> option on Windows. + + </para> + + </section> + + </section> + + <section> + <title>Linking with Libraries</title> + + <para> + + Usually, you build a library + because you want to link it with one or more programs. + You link libraries with a program by specifying + the libraries in the &cv-link-LIBS; construction variable, + and by specifying the directory in which + the library will be found in the + &cv-link-LIBPATH; construction variable: + + <!-- In the preceding paragraph, the "$" notation for + LIBS, LIBPATH etc. is used for the first time. + Maybe some words of explanation would be nice. --> + + </para> + + <scons_example name="ex2"> + <file name="SConstruct" printme="1"> + Library('foo', ['f1.c', 'f2.c', 'f3.c']) + Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.') + </file> + <file name="f1.c"> + int main() { printf("Hello, world!\n"); } + </file> + <file name="f2.c"> + int main() { printf("Hello, world!\n"); } + </file> + <file name="f3.c"> + int main() { printf("Hello, world!\n"); } + </file> + <file name="prog.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + Notice, of course, that you don't need to specify a library + prefix (like <literal>lib</literal>) + or suffix (like <literal>.a</literal> or <literal>.lib</literal>). + &SCons; uses the correct prefix or suffix for the current system. + + </para> + + <para> + + On a POSIX or Linux system, + a build of the above example would look like: + + </para> + + <scons_output example="ex2" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + On a Windows system, + a build of the above example would look like: + + </para> + + <scons_output example="ex2" os="win32"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + As usual, notice that &SCons; has taken care + of constructing the correct command lines + to link with the specified library on each system. + + </para> + + <para> + + Note also that, + if you only have a single library to link with, + you can specify the library name in single string, + instead of a Python list, + so that: + + </para> + + <sconstruct> + Program('prog.c', LIBS='foo', LIBPATH='.') + </sconstruct> + + <para> + + is equivalent to: + + </para> + + <sconstruct> + Program('prog.c', LIBS=['foo'], LIBPATH='.') + </sconstruct> + + <para> + + This is similar to the way that &SCons; + handles either a string or a list to + specify a single source file. + + </para> + + </section> + + <section> + <title>Finding Libraries: the &cv-LIBPATH; Construction Variable</title> + + <para> + + By default, the linker will only look in + certain system-defined directories for libraries. + &SCons; knows how to look for libraries + in directories that you specify with the + &cv-link-LIBPATH; construction variable. + &cv-LIBPATH; consists of a list of + directory names, like so: + + </para> + + <scons_example name="ex3"> + <file name="SConstruct" printme="1"> + Program('prog.c', LIBS = 'm', + LIBPATH = ['/usr/lib', '/usr/local/lib']) + </file> + <file name="prog.c"> + int main() { printf("prog.c\n"); } + </file> + </scons_example> + + <para> + + Using a Python list is preferred because it's portable + across systems. Alternatively, you could put all of + the directory names in a single string, separated by the + system-specific path separator character: + a colon on POSIX systems: + + </para> + + <sconstruct> + LIBPATH = '/usr/lib:/usr/local/lib' + </sconstruct> + + <para> + + or a semi-colon on Windows systems: + + </para> + + <sconstruct> + LIBPATH = 'C:\\lib;D:\\lib' + </sconstruct> + + <para> + + (Note that Python requires that the backslash + separators in a Windows path name + be escaped within strings.) + + </para> + + <para> + + When the linker is executed, + &SCons; will create appropriate flags + so that the linker will look for + libraries in the same directories as &SCons;. + So on a POSIX or Linux system, + a build of the above example would look like: + + </para> + + <scons_output example="ex3" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + On a Windows system, + a build of the above example would look like: + + </para> + + <scons_output example="ex3" os="win32"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + <!-- The link command is too wide in the PDF version. + There are some other examples of this throughout the document. --> + + <para> + + Note again that &SCons; has taken care of + the system-specific details of creating + the right command-line options. + + </para> + + </section> diff --git a/doc/user/libraries.xml b/doc/user/libraries.xml new file mode 100644 index 0000000..e3821ce --- /dev/null +++ b/doc/user/libraries.xml @@ -0,0 +1,451 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + It's often useful to organize large software projects + by collecting parts of the software into one or more libraries. + &SCons; makes it easy to create libraries + and to use them in the programs. + + </para> + + <section> + <title>Building Libraries</title> + + <para> + + You build your own libraries by specifying &b-link-Library; + instead of &b-link-Program;: + + </para> + + <programlisting> + Library('foo', ['f1.c', 'f2.c', 'f3.c']) + </programlisting> + + <para> + + &SCons; uses the appropriate library prefix and suffix for your system. + So on POSIX or Linux systems, + the above example would build as follows + (although &ranlib; may not be called on all systems): + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o f1.o -c f1.c + cc -o f2.o -c f2.c + cc -o f3.o -c f3.c + ar rc libfoo.a f1.o f2.o f3.o + ranlib libfoo.a + </screen> + + <para> + + On a Windows system, + a build of the above example would look like: + + </para> + + <screen> + C:\><userinput>scons -Q</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + cl /Fof1.obj /c f1.c /nologo + cl /Fof2.obj /c f2.c /nologo + cl /Fof3.obj /c f3.c /nologo + lib /nologo /OUT:foo.lib f1.obj f2.obj f3.obj + </screen> + + <para> + + The rules for the target name of the library + are similar to those for programs: + if you don't explicitly specify a target library name, + &SCons; will deduce one from the + name of the first source file specified, + and &SCons; will add an appropriate + file prefix and suffix if you leave them off. + + </para> + + <section> + <title>Building Libraries From Source Code or Object Files</title> + + <para> + + The previous example shows building a library from a + list of source files. + You can, however, also give the &b-link-Library; call + object files, + and it will correctly realize + In fact, you can arbitrarily mix source code files + and object files in the source list: + + </para> + + <programlisting> + Library('foo', ['f1.c', 'f2.o', 'f3.c', 'f4.o']) + </programlisting> + + <para> + + And SCons realizes that only the source code files + must be compiled into object files + before creating the final library: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o f1.o -c f1.c + cc -o f3.o -c f3.c + ar rc libfoo.a f1.o f2.o f3.o f4.o + ranlib libfoo.a + </screen> + + <para> + + Of course, in this example, the object files + must already exist for the build to succeed. + See <xref linkend="chap-nodes"></xref>, below, + for information about how you can + build object files explicitly + and include the built files in a library. + + </para> + + </section> + + <section> + <title>Building Static Libraries Explicitly: the &b-StaticLibrary; Builder</title> + + <para> + + The &b-link-Library; function builds a traditional static library. + If you want to be explicit about the type of library being built, + you can use the synonym &b-link-StaticLibrary; function + instead of &b-Library;: + + </para> + + <programlisting> + StaticLibrary('foo', ['f1.c', 'f2.c', 'f3.c']) + </programlisting> + + <para> + + There is no functional difference between the + &b-link-StaticLibrary; and &b-Library; functions. + + </para> + + </section> + + <section> + <title>Building Shared (DLL) Libraries: the &b-SharedLibrary; Builder</title> + + <para> + + If you want to build a shared library (on POSIX systems) + or a DLL file (on Windows systems), + you use the &b-link-SharedLibrary; function: + + </para> + + <programlisting> + SharedLibrary('foo', ['f1.c', 'f2.c', 'f3.c']) + </programlisting> + + <para> + + The output on POSIX: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o f1.os -c f1.c + cc -o f2.os -c f2.c + cc -o f3.os -c f3.c + cc -o libfoo.so -shared f1.os f2.os f3.os + </screen> + + <para> + + And the output on Windows: + + </para> + + <screen> + C:\><userinput>scons -Q</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + cl /Fof1.obj /c f1.c /nologo + cl /Fof2.obj /c f2.c /nologo + cl /Fof3.obj /c f3.c /nologo + link /nologo /dll /out:foo.dll /implib:foo.lib f1.obj f2.obj f3.obj + RegServerFunc(target, source, env) + </screen> + + <para> + + Notice again that &SCons; takes care of + building the output file correctly, + adding the <literal>-shared</literal> option + for a POSIX compilation, + and the <literal>/dll</literal> option on Windows. + + </para> + + </section> + + </section> + + <section> + <title>Linking with Libraries</title> + + <para> + + Usually, you build a library + because you want to link it with one or more programs. + You link libraries with a program by specifying + the libraries in the &cv-link-LIBS; construction variable, + and by specifying the directory in which + the library will be found in the + &cv-link-LIBPATH; construction variable: + + <!-- In the preceding paragraph, the "$" notation for + LIBS, LIBPATH etc. is used for the first time. + Maybe some words of explanation would be nice. --> + + </para> + + <programlisting> + Library('foo', ['f1.c', 'f2.c', 'f3.c']) + Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.') + </programlisting> + + <para> + + Notice, of course, that you don't need to specify a library + prefix (like <literal>lib</literal>) + or suffix (like <literal>.a</literal> or <literal>.lib</literal>). + &SCons; uses the correct prefix or suffix for the current system. + + </para> + + <para> + + On a POSIX or Linux system, + a build of the above example would look like: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o f1.o -c f1.c + cc -o f2.o -c f2.c + cc -o f3.o -c f3.c + ar rc libfoo.a f1.o f2.o f3.o + ranlib libfoo.a + cc -o prog.o -c prog.c + cc -o prog prog.o -L. -lfoo -lbar + </screen> + + <para> + + On a Windows system, + a build of the above example would look like: + + </para> + + <screen> + C:\><userinput>scons -Q</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + cl /Fof1.obj /c f1.c /nologo + cl /Fof2.obj /c f2.c /nologo + cl /Fof3.obj /c f3.c /nologo + lib /nologo /OUT:foo.lib f1.obj f2.obj f3.obj + cl /Foprog.obj /c prog.c /nologo + link /nologo /OUT:prog.exe /LIBPATH:. foo.lib bar.lib prog.obj + </screen> + + <para> + + As usual, notice that &SCons; has taken care + of constructing the correct command lines + to link with the specified library on each system. + + </para> + + <para> + + Note also that, + if you only have a single library to link with, + you can specify the library name in single string, + instead of a Python list, + so that: + + </para> + + <programlisting> + Program('prog.c', LIBS='foo', LIBPATH='.') + </programlisting> + + <para> + + is equivalent to: + + </para> + + <programlisting> + Program('prog.c', LIBS=['foo'], LIBPATH='.') + </programlisting> + + <para> + + This is similar to the way that &SCons; + handles either a string or a list to + specify a single source file. + + </para> + + </section> + + <section> + <title>Finding Libraries: the &cv-LIBPATH; Construction Variable</title> + + <para> + + By default, the linker will only look in + certain system-defined directories for libraries. + &SCons; knows how to look for libraries + in directories that you specify with the + &cv-link-LIBPATH; construction variable. + &cv-LIBPATH; consists of a list of + directory names, like so: + + </para> + + <programlisting> + Program('prog.c', LIBS = 'm', + LIBPATH = ['/usr/lib', '/usr/local/lib']) + </programlisting> + + <para> + + Using a Python list is preferred because it's portable + across systems. Alternatively, you could put all of + the directory names in a single string, separated by the + system-specific path separator character: + a colon on POSIX systems: + + </para> + + <programlisting> + LIBPATH = '/usr/lib:/usr/local/lib' + </programlisting> + + <para> + + or a semi-colon on Windows systems: + + </para> + + <programlisting> + LIBPATH = 'C:\\lib;D:\\lib' + </programlisting> + + <para> + + (Note that Python requires that the backslash + separators in a Windows path name + be escaped within strings.) + + </para> + + <para> + + When the linker is executed, + &SCons; will create appropriate flags + so that the linker will look for + libraries in the same directories as &SCons;. + So on a POSIX or Linux system, + a build of the above example would look like: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o prog.o -c prog.c + cc -o prog prog.o -L/usr/lib -L/usr/local/lib -lm + </screen> + + <para> + + On a Windows system, + a build of the above example would look like: + + </para> + + <screen> + C:\><userinput>scons -Q</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + cl /Foprog.obj /c prog.c /nologo + link /nologo /OUT:prog.exe /LIBPATH:\usr\lib /LIBPATH:\usr\local\lib m.lib prog.obj + </screen> + <!-- The link command is too wide in the PDF version. + There are some other examples of this throughout the document. --> + + <para> + + Note again that &SCons; has taken care of + the system-specific details of creating + the right command-line options. + + </para> + + </section> diff --git a/doc/user/main.in b/doc/user/main.in new file mode 100644 index 0000000..949a90a --- /dev/null +++ b/doc/user/main.in @@ -0,0 +1,385 @@ +<?xml version="1.0"?> +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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. + +--> + +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" +"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" +[ + + <!ENTITY % version SYSTEM "../version.xml"> + %version; + + <!ENTITY % scons SYSTEM "../scons.mod"> + %scons; + + <!ENTITY % builders-mod SYSTEM "builders.mod"> + %builders-mod; + + <!ENTITY % tools-mod SYSTEM "tools.mod"> + %tools-mod; + + <!ENTITY % variables-mod SYSTEM "variables.mod"> + %variables-mod; + + <!ENTITY actions SYSTEM "actions.xml"> + <!ENTITY alias SYSTEM "alias.xml"> + <!ENTITY ant SYSTEM "ant.xml"> + <!ENTITY build-install SYSTEM "build-install.xml"> + <!ENTITY builders SYSTEM "builders.xml"> + <!ENTITY builders-built-in SYSTEM "builders-built-in.xml"> + <!ENTITY builders-commands SYSTEM "builders-commands.xml"> + <!ENTITY builders-writing SYSTEM "builders-writing.xml"> + <!ENTITY add-method SYSTEM "add-method.xml"> + <!ENTITY caching SYSTEM "caching.xml"> + <!ENTITY command-line SYSTEM "command-line.xml"> + <!ENTITY copyright SYSTEM "copyright.xml"> + <!ENTITY depends SYSTEM "depends.xml"> + <!ENTITY environments SYSTEM "environments.xml"> + <!ENTITY errors SYSTEM "errors.xml"> + <!ENTITY example SYSTEM "example.xml"> + <!ENTITY factories SYSTEM "factories.xml"> + <!ENTITY file-removal SYSTEM "file-removal.xml"> + <!ENTITY hierarchy SYSTEM "hierarchy.xml"> + <!ENTITY java SYSTEM "java.xml"> + <!ENTITY install SYSTEM "install.xml"> + <!ENTITY less-simple SYSTEM "less-simple.xml"> + <!ENTITY libraries SYSTEM "libraries.xml"> + <!ENTITY make SYSTEM "make.xml"> + <!ENTITY mergeflags SYSTEM "mergeflags.xml"> + <!ENTITY misc SYSTEM "misc.xml"> + <!ENTITY nodes SYSTEM "nodes.xml"> + <!ENTITY output SYSTEM "output.xml"> + <!ENTITY parseconfig SYSTEM "parseconfig.xml"> + <!ENTITY parseflags SYSTEM "parseflags.xml"> + <!ENTITY preface SYSTEM "preface.xml"> + <!ENTITY python SYSTEM "python.xml"> + <!ENTITY repositories SYSTEM "repositories.xml"> + <!ENTITY run SYSTEM "run.xml"> + <!ENTITY scanners SYSTEM "scanners.xml"> + <!ENTITY sconf SYSTEM "sconf.xml"> + <!ENTITY separate SYSTEM "separate.xml"> + <!ENTITY simple SYSTEM "simple.xml"> + <!ENTITY sourcecode SYSTEM "sourcecode.xml"> + <!ENTITY tasks SYSTEM "tasks.xml"> + <!ENTITY tools SYSTEM "tools.xml"> + <!ENTITY troubleshoot SYSTEM "troubleshoot.xml"> + <!ENTITY variables-xml SYSTEM "variables.xml"> + <!ENTITY variants SYSTEM "variants.xml"> + + <!ENTITY builders-gen SYSTEM "builders.gen"> + <!ENTITY tools-gen SYSTEM "tools.gen"> + <!ENTITY variables-gen SYSTEM "variables.gen"> + +]> + + <!-- + + XXX FindFile() + XXX FindPathDirs() + XXX GetBuildPath() + XXX GetLaunchDir() + + XXX ParseDepends() + XXX Platform() + XXX SConsignFile() + XXX Tools() + + XXX GetOption('duplicate') + XXX SetOption('duplicate') + XXX - - duplicate= + + XXX CheckTypeSize() + + XXX - - diskcheck= + + XXX - - warn= + + --> + +<book> + <bookinfo> + <title>SCons User Guide &buildversion;</title> + + <author> + <firstname>Steven</firstname> + <surname>Knight</surname> + </author> + + <edition>Revision &buildrevision; (&builddate;)</edition> + + <pubdate>2004, 2005, 2006, 2007, 2008</pubdate> + + <copyright> + <year>2004, 2005, 2006, 2007, 2008</year> + <holder>Steven Knight</holder> + </copyright> + + <legalnotice> + ©right; + </legalnotice> + + <releaseinfo>version &buildversion;</releaseinfo> + + </bookinfo> + + <preface id="chap-preface"> + <title>Preface</title> + &preface; + </preface> + + <chapter id="chap-build-install"> + <title>Building and Installing &SCons;</title> + &build-install; + </chapter> + + <chapter id="chap-simple"> + <title>Simple Builds</title> + &simple; + </chapter> + + <chapter id="chap-less-simple"> + <title>Less Simple Things to Do With Builds</title> + &less-simple; + </chapter> + + <chapter id="chap-libraries"> + <title>Building and Linking with Libraries</title> + &libraries; + </chapter> + + <chapter id="chap-nodes"> + <title>Node Objects</title> + &nodes; + </chapter> + + <chapter id="chap-depends"> + <title>Dependencies</title> + &depends; + </chapter> + + <chapter id="chap-environments"> + <title>Environments</title> + &environments; + </chapter> + + <!-- These next three sections should be combined into one chapter --> + <chapter id="chap-mergeflags"> + <title>Merging Options into the Environment: the &MergeFlags; Function</title> + &mergeflags; + </chapter> + <chapter id="chap-parseflags"> + <title>Separating Compile Arguments into their Variables: the &ParseFlags; Function</title> + &parseflags; + </chapter> + <chapter id="chap-parseconfig"> + <title>Finding Installed Library Information: the &ParseConfig; Function</title> + &parseconfig; + </chapter> + + <chapter id="chap-output"> + <title>Controlling Build Output</title> + &output; + </chapter> + + <chapter id="chap-command-line"> + <title>Controlling a Build From the Command Line</title> + &command-line; + </chapter> + + <chapter id="chap-install"> + <title>Installing Files in Other Directories: the &Install; Builder</title> + &install; + </chapter> + + <chapter id="chap-factories"> + <title>Platform-Independent File System Manipulation</title> + &factories; + </chapter> + + <chapter id="chap-file-removal"> + <title>Controlling Removal of Targets</title> + &file-removal; + </chapter> + + <chapter id="chap-hierarchical"> + <title>Hierarchical Builds</title> + &hierarchy; + </chapter> + + <chapter id="chap-separate"> + <title>Separating Source and Build Directories</title> + &separate; + </chapter> + + <chapter id="chap-variants"> + <title>Variant Builds</title> + &variants; + </chapter> + + <!-- + + <chapter id="chap-builders-built-in"> + <title>Built-In Builders</title> + &builders-built-in; + </chapter> + + --> + + <chapter id="chap-builders-writing"> + <title>Writing Your Own Builders</title> + &builders-writing; + </chapter> + + <chapter id="chap-builders-commands"> + <title>Not Writing a Builder: the &Command; Builder</title> + &builders-commands; + </chapter> + + <chapter id="chap-add-method"> + <title>Pseudo-Builders: the AddMethod function</title> + &add-method; + </chapter> + + <!-- + + XXX Action() + XXX AddPostAction() + XXX AddPreAction() + + <chapter id="chap-actions"> + <title>&SCons; Actions</title> + &actions; + </chapter> + + --> + + <chapter id="chap-scanners"> + <title>Writing Scanners</title> + &scanners; + </chapter> + + <chapter id="chap-repositories"> + <title>Building From Code Repositories</title> + &repositories; + </chapter> + + <chapter id="chap-sconf"> + <title>Multi-Platform Configuration (&Autoconf; Functionality)</title> + &sconf; + </chapter> + + <!-- + + <chapter id="chap-sourcecode"> + <title>Fetching Files From Source Code Management Systems</title> + &sourcecode; + </chapter> + + --> + + <chapter id="chap-caching"> + <title>Caching Built Files</title> + &caching; + </chapter> + + <chapter id="chap-alias"> + <title>Alias Targets</title> + &alias; + </chapter> + + <chapter id="chap-java"> + <title>Java Builds</title> + &java; + </chapter> + + <!-- + + <chapter id="chap-run"> + <title>How to Run &SCons;</title> + &run; + </chapter> + + --> + + <chapter id="chap-misc"> + <title>Miscellaneous Functionality</title> + &misc; + </chapter> + + <chapter id="chap-troubleshooting"> + <title>Troubleshooting</title> + &troubleshoot; + </chapter> + + <appendix id="app-variables"> + <title>Construction Variables</title> + &variables-xml; + </appendix> + + <appendix id="app-builders"> + <title>Builders</title> + &builders; + </appendix> + + <appendix id="app-tools"> + <title>Tools</title> + &tools; + </appendix> + + <appendix id="app-tasks"> + <title>Handling Common Tasks</title> + &tasks; + </appendix> + + <!-- + + <appendix id="app-python"> + <title>Python Overview</title> + &example; + </appendix> + + <appendix id="app-example"> + <title>Complex &SCons; Example</title> + &example; + </appendix> + + <appendix id="app-make"> + <title>Converting From Make</title> + &make; + </appendix> + + <appendix id="app-cons"> + <title>Converting From Cons</title> + &cons; + </appendix> + + <appendix id="app-ant"> + <title>Converting From Ant</title> + &ant; + </appendix> + + --> + +</book> diff --git a/doc/user/main.xml b/doc/user/main.xml new file mode 100644 index 0000000..949a90a --- /dev/null +++ b/doc/user/main.xml @@ -0,0 +1,385 @@ +<?xml version="1.0"?> +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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. + +--> + +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" +"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" +[ + + <!ENTITY % version SYSTEM "../version.xml"> + %version; + + <!ENTITY % scons SYSTEM "../scons.mod"> + %scons; + + <!ENTITY % builders-mod SYSTEM "builders.mod"> + %builders-mod; + + <!ENTITY % tools-mod SYSTEM "tools.mod"> + %tools-mod; + + <!ENTITY % variables-mod SYSTEM "variables.mod"> + %variables-mod; + + <!ENTITY actions SYSTEM "actions.xml"> + <!ENTITY alias SYSTEM "alias.xml"> + <!ENTITY ant SYSTEM "ant.xml"> + <!ENTITY build-install SYSTEM "build-install.xml"> + <!ENTITY builders SYSTEM "builders.xml"> + <!ENTITY builders-built-in SYSTEM "builders-built-in.xml"> + <!ENTITY builders-commands SYSTEM "builders-commands.xml"> + <!ENTITY builders-writing SYSTEM "builders-writing.xml"> + <!ENTITY add-method SYSTEM "add-method.xml"> + <!ENTITY caching SYSTEM "caching.xml"> + <!ENTITY command-line SYSTEM "command-line.xml"> + <!ENTITY copyright SYSTEM "copyright.xml"> + <!ENTITY depends SYSTEM "depends.xml"> + <!ENTITY environments SYSTEM "environments.xml"> + <!ENTITY errors SYSTEM "errors.xml"> + <!ENTITY example SYSTEM "example.xml"> + <!ENTITY factories SYSTEM "factories.xml"> + <!ENTITY file-removal SYSTEM "file-removal.xml"> + <!ENTITY hierarchy SYSTEM "hierarchy.xml"> + <!ENTITY java SYSTEM "java.xml"> + <!ENTITY install SYSTEM "install.xml"> + <!ENTITY less-simple SYSTEM "less-simple.xml"> + <!ENTITY libraries SYSTEM "libraries.xml"> + <!ENTITY make SYSTEM "make.xml"> + <!ENTITY mergeflags SYSTEM "mergeflags.xml"> + <!ENTITY misc SYSTEM "misc.xml"> + <!ENTITY nodes SYSTEM "nodes.xml"> + <!ENTITY output SYSTEM "output.xml"> + <!ENTITY parseconfig SYSTEM "parseconfig.xml"> + <!ENTITY parseflags SYSTEM "parseflags.xml"> + <!ENTITY preface SYSTEM "preface.xml"> + <!ENTITY python SYSTEM "python.xml"> + <!ENTITY repositories SYSTEM "repositories.xml"> + <!ENTITY run SYSTEM "run.xml"> + <!ENTITY scanners SYSTEM "scanners.xml"> + <!ENTITY sconf SYSTEM "sconf.xml"> + <!ENTITY separate SYSTEM "separate.xml"> + <!ENTITY simple SYSTEM "simple.xml"> + <!ENTITY sourcecode SYSTEM "sourcecode.xml"> + <!ENTITY tasks SYSTEM "tasks.xml"> + <!ENTITY tools SYSTEM "tools.xml"> + <!ENTITY troubleshoot SYSTEM "troubleshoot.xml"> + <!ENTITY variables-xml SYSTEM "variables.xml"> + <!ENTITY variants SYSTEM "variants.xml"> + + <!ENTITY builders-gen SYSTEM "builders.gen"> + <!ENTITY tools-gen SYSTEM "tools.gen"> + <!ENTITY variables-gen SYSTEM "variables.gen"> + +]> + + <!-- + + XXX FindFile() + XXX FindPathDirs() + XXX GetBuildPath() + XXX GetLaunchDir() + + XXX ParseDepends() + XXX Platform() + XXX SConsignFile() + XXX Tools() + + XXX GetOption('duplicate') + XXX SetOption('duplicate') + XXX - - duplicate= + + XXX CheckTypeSize() + + XXX - - diskcheck= + + XXX - - warn= + + --> + +<book> + <bookinfo> + <title>SCons User Guide &buildversion;</title> + + <author> + <firstname>Steven</firstname> + <surname>Knight</surname> + </author> + + <edition>Revision &buildrevision; (&builddate;)</edition> + + <pubdate>2004, 2005, 2006, 2007, 2008</pubdate> + + <copyright> + <year>2004, 2005, 2006, 2007, 2008</year> + <holder>Steven Knight</holder> + </copyright> + + <legalnotice> + ©right; + </legalnotice> + + <releaseinfo>version &buildversion;</releaseinfo> + + </bookinfo> + + <preface id="chap-preface"> + <title>Preface</title> + &preface; + </preface> + + <chapter id="chap-build-install"> + <title>Building and Installing &SCons;</title> + &build-install; + </chapter> + + <chapter id="chap-simple"> + <title>Simple Builds</title> + &simple; + </chapter> + + <chapter id="chap-less-simple"> + <title>Less Simple Things to Do With Builds</title> + &less-simple; + </chapter> + + <chapter id="chap-libraries"> + <title>Building and Linking with Libraries</title> + &libraries; + </chapter> + + <chapter id="chap-nodes"> + <title>Node Objects</title> + &nodes; + </chapter> + + <chapter id="chap-depends"> + <title>Dependencies</title> + &depends; + </chapter> + + <chapter id="chap-environments"> + <title>Environments</title> + &environments; + </chapter> + + <!-- These next three sections should be combined into one chapter --> + <chapter id="chap-mergeflags"> + <title>Merging Options into the Environment: the &MergeFlags; Function</title> + &mergeflags; + </chapter> + <chapter id="chap-parseflags"> + <title>Separating Compile Arguments into their Variables: the &ParseFlags; Function</title> + &parseflags; + </chapter> + <chapter id="chap-parseconfig"> + <title>Finding Installed Library Information: the &ParseConfig; Function</title> + &parseconfig; + </chapter> + + <chapter id="chap-output"> + <title>Controlling Build Output</title> + &output; + </chapter> + + <chapter id="chap-command-line"> + <title>Controlling a Build From the Command Line</title> + &command-line; + </chapter> + + <chapter id="chap-install"> + <title>Installing Files in Other Directories: the &Install; Builder</title> + &install; + </chapter> + + <chapter id="chap-factories"> + <title>Platform-Independent File System Manipulation</title> + &factories; + </chapter> + + <chapter id="chap-file-removal"> + <title>Controlling Removal of Targets</title> + &file-removal; + </chapter> + + <chapter id="chap-hierarchical"> + <title>Hierarchical Builds</title> + &hierarchy; + </chapter> + + <chapter id="chap-separate"> + <title>Separating Source and Build Directories</title> + &separate; + </chapter> + + <chapter id="chap-variants"> + <title>Variant Builds</title> + &variants; + </chapter> + + <!-- + + <chapter id="chap-builders-built-in"> + <title>Built-In Builders</title> + &builders-built-in; + </chapter> + + --> + + <chapter id="chap-builders-writing"> + <title>Writing Your Own Builders</title> + &builders-writing; + </chapter> + + <chapter id="chap-builders-commands"> + <title>Not Writing a Builder: the &Command; Builder</title> + &builders-commands; + </chapter> + + <chapter id="chap-add-method"> + <title>Pseudo-Builders: the AddMethod function</title> + &add-method; + </chapter> + + <!-- + + XXX Action() + XXX AddPostAction() + XXX AddPreAction() + + <chapter id="chap-actions"> + <title>&SCons; Actions</title> + &actions; + </chapter> + + --> + + <chapter id="chap-scanners"> + <title>Writing Scanners</title> + &scanners; + </chapter> + + <chapter id="chap-repositories"> + <title>Building From Code Repositories</title> + &repositories; + </chapter> + + <chapter id="chap-sconf"> + <title>Multi-Platform Configuration (&Autoconf; Functionality)</title> + &sconf; + </chapter> + + <!-- + + <chapter id="chap-sourcecode"> + <title>Fetching Files From Source Code Management Systems</title> + &sourcecode; + </chapter> + + --> + + <chapter id="chap-caching"> + <title>Caching Built Files</title> + &caching; + </chapter> + + <chapter id="chap-alias"> + <title>Alias Targets</title> + &alias; + </chapter> + + <chapter id="chap-java"> + <title>Java Builds</title> + &java; + </chapter> + + <!-- + + <chapter id="chap-run"> + <title>How to Run &SCons;</title> + &run; + </chapter> + + --> + + <chapter id="chap-misc"> + <title>Miscellaneous Functionality</title> + &misc; + </chapter> + + <chapter id="chap-troubleshooting"> + <title>Troubleshooting</title> + &troubleshoot; + </chapter> + + <appendix id="app-variables"> + <title>Construction Variables</title> + &variables-xml; + </appendix> + + <appendix id="app-builders"> + <title>Builders</title> + &builders; + </appendix> + + <appendix id="app-tools"> + <title>Tools</title> + &tools; + </appendix> + + <appendix id="app-tasks"> + <title>Handling Common Tasks</title> + &tasks; + </appendix> + + <!-- + + <appendix id="app-python"> + <title>Python Overview</title> + &example; + </appendix> + + <appendix id="app-example"> + <title>Complex &SCons; Example</title> + &example; + </appendix> + + <appendix id="app-make"> + <title>Converting From Make</title> + &make; + </appendix> + + <appendix id="app-cons"> + <title>Converting From Cons</title> + &cons; + </appendix> + + <appendix id="app-ant"> + <title>Converting From Ant</title> + &ant; + </appendix> + + --> + +</book> diff --git a/doc/user/make.in b/doc/user/make.in new file mode 100644 index 0000000..e778c61 --- /dev/null +++ b/doc/user/make.in @@ -0,0 +1,121 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 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> + + XXX + + </para> + + <section> + <title>Differences Between &Make; and &SCons;</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Advantages of &SCons; Over &Make;</title> + + <para> + + XXX + + </para> + + </section> diff --git a/doc/user/make.xml b/doc/user/make.xml new file mode 100644 index 0000000..e778c61 --- /dev/null +++ b/doc/user/make.xml @@ -0,0 +1,121 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 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> + + XXX + + </para> + + <section> + <title>Differences Between &Make; and &SCons;</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Advantages of &SCons; Over &Make;</title> + + <para> + + XXX + + </para> + + </section> diff --git a/doc/user/mergeflags.in b/doc/user/mergeflags.in new file mode 100644 index 0000000..b50992b --- /dev/null +++ b/doc/user/mergeflags.in @@ -0,0 +1,137 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; construction environments have a &MergeFlags; method + that merges a dictionary of values into the construction environment. + &MergeFlags; treats each value in the dictionary + as a list of options such as one might pass to a command + (such as a compiler or linker). + &MergeFlags; will not duplicate an option + if it already exists in the construction environment variable. + + </para> + + <para> + + &MergeFlags; tries to be intelligent about merging options. + When merging options to any variable + whose name ends in <varname>PATH</varname>, + &MergeFlags; keeps the leftmost occurrence of the option, + because in typical lists of directory paths, + the first occurrence "wins." + When merging options to any other variable name, + &MergeFlags; keeps the rightmost occurrence of the option, + because in a list of typical command-line options, + the last occurrence "wins." + + </para> + + <scons_example name="MergeFlags1"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Append(CCFLAGS = '-option -O3 -O1') + flags = { 'CCFLAGS' : '-whatever -O3' } + env.MergeFlags(flags) + print env['CCFLAGS'] + </file> + </scons_example> + + <scons_output example="MergeFlags1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Note that the default value for &cv-link-CCFLAGS; + <!-- + [TODO: for when we make CLVar public] + is a <varname>CLVar</varname>, + --> + is an internal &SCons; object + which automatically converts + the options we specified as a string into a list. + + </para> + + <scons_example name="MergeFlags2"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include']) + flags = { 'CPPPATH' : ['/usr/opt/include', '/usr/local/include'] } + env.MergeFlags(flags) + print env['CPPPATH'] + </file> + </scons_example> + + <scons_output example="MergeFlags2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Note that the default value for &cv-link-CPPPATH; + <!-- + [TODO: for when we make CLVar public] + is a Python list, not a <varname>CLVar</varname>, + --> + is a normal Python list, + so we must specify its values as a list + in the dictionary we pass to the &MergeFlags; function. + + </para> + + <para> + + If &MergeFlags; is passed anything other than a dictionary, + it calls the &ParseFlags; method to convert it into a dictionary. + + </para> + + <scons_example name="MergeFlags3"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Append(CCFLAGS = '-option -O3 -O1') + env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include']) + env.MergeFlags('-whatever -I/usr/opt/include -O3 -I/usr/local/include') + print env['CCFLAGS'] + print env['CPPPATH'] + </file> + </scons_example> + + <scons_output example="MergeFlags3"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + In the combined example above, + &ParseFlags; has sorted the options into their corresponding variables + and returned a dictionary for &MergeFlags; to apply + to the construction variables + in the specified construction environment. + + </para> diff --git a/doc/user/mergeflags.xml b/doc/user/mergeflags.xml new file mode 100644 index 0000000..7edc986 --- /dev/null +++ b/doc/user/mergeflags.xml @@ -0,0 +1,138 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; construction environments have a &MergeFlags; method + that merges a dictionary of values into the construction environment. + &MergeFlags; treats each value in the dictionary + as a list of options such as one might pass to a command + (such as a compiler or linker). + &MergeFlags; will not duplicate an option + if it already exists in the construction environment variable. + + </para> + + <para> + + &MergeFlags; tries to be intelligent about merging options. + When merging options to any variable + whose name ends in <varname>PATH</varname>, + &MergeFlags; keeps the leftmost occurrence of the option, + because in typical lists of directory paths, + the first occurrence "wins." + When merging options to any other variable name, + &MergeFlags; keeps the rightmost occurrence of the option, + because in a list of typical command-line options, + the last occurrence "wins." + + </para> + + <programlisting> + env = Environment() + env.Append(CCFLAGS = '-option -O3 -O1') + flags = { 'CCFLAGS' : '-whatever -O3' } + env.MergeFlags(flags) + print env['CCFLAGS'] + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + ['-option', '-O1', '-whatever', '-O3'] + scons: `.' is up to date. + </screen> + + <para> + + Note that the default value for &cv-link-CCFLAGS; + <!-- + [TODO: for when we make CLVar public] + is a <varname>CLVar</varname>, + --> + is an internal &SCons; object + which automatically converts + the options we specified as a string into a list. + + </para> + + <programlisting> + env = Environment() + env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include']) + flags = { 'CPPPATH' : ['/usr/opt/include', '/usr/local/include'] } + env.MergeFlags(flags) + print env['CPPPATH'] + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + ['/include', '/usr/local/include', '/usr/include', '/usr/opt/include'] + scons: `.' is up to date. + </screen> + + <para> + + Note that the default value for &cv-link-CPPPATH; + <!-- + [TODO: for when we make CLVar public] + is a Python list, not a <varname>CLVar</varname>, + --> + is a normal Python list, + so we must specify its values as a list + in the dictionary we pass to the &MergeFlags; function. + + </para> + + <para> + + If &MergeFlags; is passed anything other than a dictionary, + it calls the &ParseFlags; method to convert it into a dictionary. + + </para> + + <programlisting> + env = Environment() + env.Append(CCFLAGS = '-option -O3 -O1') + env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include']) + env.MergeFlags('-whatever -I/usr/opt/include -O3 -I/usr/local/include') + print env['CCFLAGS'] + print env['CPPPATH'] + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + ['-option', '-O1', '-whatever', '-O3'] + ['/include', '/usr/local/include', '/usr/include', '/usr/opt/include'] + scons: `.' is up to date. + </screen> + + <para> + + In the combined example above, + &ParseFlags; has sorted the options into their corresponding variables + and returned a dictionary for &MergeFlags; to apply + to the construction variables + in the specified construction environment. + + </para> diff --git a/doc/user/misc.in b/doc/user/misc.in new file mode 100644 index 0000000..6679134 --- /dev/null +++ b/doc/user/misc.in @@ -0,0 +1,606 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; supports a lot of additional functionality + that doesn't readily fit into the other chapters. + + </para> + + <section> + <title>Verifying the Python Version: the &EnsurePythonVersion; Function</title> + + <para> + + Although the &SCons; code itself will run + on any Python version 1.5.2 or later, + you are perfectly free to make use of + Python syntax and modules from more modern versions + (for example, Python 2.4 or 2.5) + when writing your &SConscript; files + or your own local modules. + If you do this, it's usually helpful to + configure &SCons; to exit gracefully with an error message + if it's being run with a version of Python + that simply won't work with your code. + This is especially true if you're going to use &SCons; + to build source code that you plan to distribute publicly, + where you can't be sure of the Python version + that an anonymous remote user might use + to try to build your software. + + </para> + + <para> + + &SCons; provides an &EnsurePythonVersion; function for this. + You simply pass it the major and minor versions + numbers of the version of Python you require: + + </para> + + <!-- + + TODO: Figure out how to generate the error message + regardless of executing Python version by faking out + the infrastructure in some way. + + <scons_example name="EnsurePythonVersion"> + <file name="SConstruct" printme="1"> + EnsurePythonVersion(2, 5) + </file> + </scons_example> + + --> + + <sconstruct> + EnsurePythonVersion(2, 5) + </sconstruct> + + <para> + + And then &SCons will exit with the following error + message when a user runs it with an unsupported + earlier version of Python: + + </para> + + <!-- + + TODO: Figure out how to generate the error message + regardless of executing Python version by faking out + the infrastructure in some way. + + <scons_output example="EnsurePythonVersion"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + Python 2.5 or greater required, but you have Python 2.3.6 + </screen> + + </section> + + <section> + <title>Verifying the SCons Version: the &EnsureSConsVersion; Function</title> + + <para> + + You may, of course, write your &SConscript; files + to use features that were only added in + recent versions of &SCons;. + When you publicly distribute software that is built using &SCons;, + it's helpful to have &SCons; + verify the version being used and + exit gracefully with an error message + if the user's version of &SCons; won't work + with your &SConscript; files. + &SCons; provides an &EnsureSConsVersion; function + that verifies the version of &SCons; + in the same + the &EnsurePythonVersion; function + verifies the version of Python, + by passing in the major and minor versions + numbers of the version of SCons you require: + + </para> + + <!-- + + TODO: Figure out how to generate the error message + regardless of executing SCons version by faking out + the infrastructure in some way. + + <scons_example name="EnsureSConsVersion"> + <file name="SConstruct" printme="1"> + EnsureSConsVersion(1, 0) + </file> + </scons_example> + + --> + + <sconstruct> + EnsureSConsVersion(1, 0) + </sconstruct> + + <para> + + And then &SCons will exit with the following error + message when a user runs it with an unsupported + earlier version of &SCons;: + + </para> + + <!-- + + TODO: Figure out how to generate the error message + regardless of executing SCons version by faking out + the infrastructure in some way. + + <scons_output example="EnsureSConsVersion"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + SCons 1.0 or greater required, but you have SCons 0.98.5 + </screen> + + </section> + + <section> + <title>Explicitly Terminating &SCons; While Reading &SConscript; Files: the &Exit; Function</title> + + <para> + + &SCons; supports an &Exit; function + which can be used to terminate &SCons; + while reading the &SConscript; files, + usually because you've detected a condition + under which it doesn't make sense to proceed: + + </para> + + <scons_example name="Exit"> + <file name="SConstruct" printme="1"> + if ARGUMENTS.get('FUTURE'): + print "The FUTURE option is not supported yet!" + Exit(2) + env = Environment() + env.Program('hello.c') + </file> + <file name="hello.c"> + hello.c + </file> + </scons_example> + + <scons_output example="Exit"> + <scons_output_command>scons -Q FUTURE=1</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + The &Exit; function takes as an argument + the (numeric) exit status that you want &SCons; to exit with. + If you don't specify a value, + the default is to exit with <literal>0</literal>, + which indicates successful execution. + + </para> + + <para> + + Note that the &Exit; function + is equivalent to calling the Python + <function>sys.exit</function> function + (which the it actually calls), + but because &Exit; is a &SCons; function, + you don't have to import the Python + <literal>sys</literal> module to use it. + + </para> + + </section> + + <section> + <title>Searching for Files: the &FindFile; Function</title> + + <para> + + The &FindFile; function searches for a file in a list of directories. + If there is only one directory, it can be given as a simple string. + The function returns a File node if a matching file exists, + or None if no file is found. + (See the documentation for the &Glob; function for an alternative way + of searching for entries in a directory.) + + </para> + + <scons_example name="FindFile1a"> + <file name="SConstruct" printme="1"> + # one directory + print FindFile('missing', '.') + t = FindFile('exists', '.') + print t.__class__, t + </file> + <file name="exists"> + exists + </file> + </scons_example> + + <scons_output example="FindFile1a" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <scons_example name="FindFile1b"> + <file name="SConstruct" printme="1"> + # several directories + includes = [ '.', 'include', 'src/include'] + headers = [ 'nonesuch.h', 'config.h', 'private.h', 'dist.h'] + for hdr in headers: + print '%-12s' % ('%s:' % hdr), FindFile(hdr, includes) + </file> + <file name="config.h"> + exists + </file> + <directory name="src"></directory> + <directory name="src/include"></directory> + </file> + <file name="src/include/private.h"> + exists + <directory name="include"></directory> + </file> + <file name="include/dist.h"> + exists + </scons_example> + + <scons_output example="FindFile1b" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <!-- The man page says this should work, but it fails. + <para> + + If the 'file' parameter is a list of files, + a list of File nodes is returned. + + </para> + + <scons_example name="FindFile1c"> + <file name="SConstruct" printme="1"> + # several directories + includes = [ '.', 'include', 'src/include'] + headers = [ 'nonesuch.h', 'config.h', 'private.h', 'dist.h'] + print FindFile(headers, includes) + </file> + <file name="config.h"> + exists + </file> + <directory name="src"></directory> + <directory name="src/include"></directory> + </file> + <file name="src/include/private.h"> + exists + <directory name="include"></directory> + </file> + <file name="include/dist.h"> + exists + </scons_example> + + <scons_output example="FindFile1c" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + --> + + <para> + + If the file exists in more than one directory, + only the first occurrence is returned. + + </para> + + <scons_example name="FindFile1d"> + <file name="SConstruct" printme="1"> + print FindFile('multiple', ['sub1', 'sub2', 'sub3']) + print FindFile('multiple', ['sub2', 'sub3', 'sub1']) + print FindFile('multiple', ['sub3', 'sub1', 'sub2']) + </file> + <directory name="sub1"></directory> + <file name="sub1/multiple"> + exists + </file> + <directory name="sub2"></directory> + <file name="sub2/multiple"> + exists + </file> + <directory name="sub3"></directory> + <file name="sub3/multiple"> + exists + </file> + </scons_example> + + <scons_output example="FindFile1d" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <!-- file may be a list of file names or a single file name. --> + + <para> + + In addition to existing files, &FindFile; will also find derived files + (that is, non-leaf files) that haven't been built yet. + (Leaf files should already exist, or the build will fail!) + + </para> + + <scons_example name="FindFile2"> + <file name="SConstruct" printme="1"> + # Neither file exists, so build will fail + Command('derived', 'leaf', 'cat >$TARGET $SOURCE') + print FindFile('leaf', '.') + print FindFile('derived', '.') + </file> + </scons_example> + + <scons_output example="FindFile2" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <scons_example name="FindFile2"> + <file name="SConstruct" printme="1"> + # Only 'leaf' exists + Command('derived', 'leaf', 'cat >$TARGET $SOURCE') + print FindFile('leaf', '.') + print FindFile('derived', '.') + </file> + <file name="leaf"> + leaf + </file> + </scons_example> + + <scons_output example="FindFile2" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + If a source file exists, &FindFile; will correctly return the name + in the build directory. + + </para> + + <scons_example name="FindFile3"> + <file name="SConstruct" printme="1"> + # Only 'src/leaf' exists + VariantDir('build', 'src') + print FindFile('leaf', 'build') + </file> + <directory name="src"></directory> + <file name="src/leaf"> + leaf + </file> + </scons_example> + + <scons_output example="FindFile3" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Handling Nested Lists: the &Flatten; Function</title> + + <para> + + &SCons; supports a &Flatten; function + which takes an input Python sequence + (list or tuple) + and returns a flattened list + containing just the individual elements of + the sequence. + This can be handy when trying to examine + a list composed of the lists + returned by calls to various Builders. + For example, you might collect + object files built in different ways + into one call to the &Program; Builder + by just enclosing them in a list, as follows: + + </para> + + <scons_example name="Flatten1"> + <file name="SConstruct" printme="1"> + objects = [ + Object('prog1.c'), + Object('prog2.c', CCFLAGS='-DFOO'), + ] + Program(objects) + </file> + <file name="prog1.c"> + prog1.c + </file> + <file name="prog2.c"> + prog2.c + </file> + </scons_example> + + <para> + + Because the Builder calls in &SCons; + flatten their input lists, + this works just fine to build the program: + + </para> + + <scons_output example="Flatten1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + But if you were debugging your build + and wanted to print the absolute path + of each object file in the + <varname>objects</varname> list, + you might try the following simple approach, + trying to print each Node's + <literal>abspath</literal> + attribute: + + </para> + + <scons_example name="Flatten2"> + <file name="SConstruct" printme="1"> + objects = [ + Object('prog1.c'), + Object('prog2.c', CCFLAGS='-DFOO'), + ] + Program(objects) + + for object_file in objects: + print object_file.abspath + </file> + <file name="prog1.c"> + prog1.c + </file> + <file name="prog2.c"> + prog2.c + </file> + </scons_example> + + <para> + + This does not work as expected + because each call to <function>str</function> + is operating an embedded list returned by + each &Object; call, + not on the underlying Nodes within those lists: + + </para> + + <scons_output example="Flatten2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + The solution is to use the &Flatten; function + so that you can pass each Node to + the <function>str</function> separately: + + </para> + + <scons_example name="Flatten3"> + <file name="SConstruct" printme="1"> + objects = [ + Object('prog1.c'), + Object('prog2.c', CCFLAGS='-DFOO'), + ] + Program(objects) + + for object_file in Flatten(objects): + print object_file.abspath + </file> + <file name="prog1.c"> + prog1.c + </file> + <file name="prog2.c"> + prog2.c + </file> + </scons_example> + + <!-- + + TODO: can't use this now because it displays the temporary path name + + <scons_output example="Flatten3"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + /home/me/project/prog1.o + /home/me/project/prog2.o + cc -o prog1.o -c prog1.c + cc -o prog2.o -c -DFOO prog2.c + cc -o prog1 prog1.o prog2.o + </screen> + + </section> + + <section> + <title>Finding the Invocation Directory: the &GetLaunchDir; Function</title> + + <para> + + If you need to find the directory from + which the user invoked the &scons; command, + you can use the &GetLaunchDir; function: + + </para> + + <sconstruct> + env = Environment( + LAUNCHDIR = GetLaunchDir(), + ) + env.Command('directory_build_info', + '$LAUNCHDIR/build_info' + Copy('$TARGET', '$SOURCE')) + </sconstruct> + + <para> + + Because &SCons; is usually invoked from the top-level + directory in which the &SConstruct; file lives, + the Python <function>os.getcwd()</function> + is often equivalent. + However, the &SCons; + <literal>-u</literal>, + <literal>-U</literal> + and + <literal>-D</literal> + command-line options, + when invoked from a subdirectory, + will cause &SCons; to change to the directory + in which the &SConstruct; file is found. + When those options are used, + &GetLaunchDir; will still return the path to the + user's invoking subdirectory, + allowing the &SConscript; configuration + to still get at configuration (or other) files + from the originating directory. + + </para> + + </section> diff --git a/doc/user/misc.xml b/doc/user/misc.xml new file mode 100644 index 0000000..a2305ee --- /dev/null +++ b/doc/user/misc.xml @@ -0,0 +1,565 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; supports a lot of additional functionality + that doesn't readily fit into the other chapters. + + </para> + + <section> + <title>Verifying the Python Version: the &EnsurePythonVersion; Function</title> + + <para> + + Although the &SCons; code itself will run + on any Python version 1.5.2 or later, + you are perfectly free to make use of + Python syntax and modules from more modern versions + (for example, Python 2.4 or 2.5) + when writing your &SConscript; files + or your own local modules. + If you do this, it's usually helpful to + configure &SCons; to exit gracefully with an error message + if it's being run with a version of Python + that simply won't work with your code. + This is especially true if you're going to use &SCons; + to build source code that you plan to distribute publicly, + where you can't be sure of the Python version + that an anonymous remote user might use + to try to build your software. + + </para> + + <para> + + &SCons; provides an &EnsurePythonVersion; function for this. + You simply pass it the major and minor versions + numbers of the version of Python you require: + + </para> + + <!-- + + TODO: Figure out how to generate the error message + regardless of executing Python version by faking out + the infrastructure in some way. + + <scons_example name="EnsurePythonVersion"> + <file name="SConstruct" printme="1"> + EnsurePythonVersion(2, 5) + </file> + </scons_example> + + --> + + <programlisting> + EnsurePythonVersion(2, 5) + </programlisting> + + <para> + + And then &SCons; will exit with the following error + message when a user runs it with an unsupported + earlier version of Python: + + </para> + + <!-- + + TODO: Figure out how to generate the error message + regardless of executing Python version by faking out + the infrastructure in some way. + + <scons_output example="EnsurePythonVersion"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + Python 2.5 or greater required, but you have Python 2.3.6 + </screen> + + </section> + + <section> + <title>Verifying the SCons Version: the &EnsureSConsVersion; Function</title> + + <para> + + You may, of course, write your &SConscript; files + to use features that were only added in + recent versions of &SCons;. + When you publicly distribute software that is built using &SCons;, + it's helpful to have &SCons; + verify the version being used and + exit gracefully with an error message + if the user's version of &SCons; won't work + with your &SConscript; files. + &SCons; provides an &EnsureSConsVersion; function + that verifies the version of &SCons; + in the same + the &EnsurePythonVersion; function + verifies the version of Python, + by passing in the major and minor versions + numbers of the version of SCons you require: + + </para> + + <!-- + + TODO: Figure out how to generate the error message + regardless of executing SCons version by faking out + the infrastructure in some way. + + <scons_example name="EnsureSConsVersion"> + <file name="SConstruct" printme="1"> + EnsureSConsVersion(1, 0) + </file> + </scons_example> + + --> + + <programlisting> + EnsureSConsVersion(1, 0) + </programlisting> + + <para> + + And then &SCons; will exit with the following error + message when a user runs it with an unsupported + earlier version of &SCons;: + + </para> + + <!-- + + TODO: Figure out how to generate the error message + regardless of executing SCons version by faking out + the infrastructure in some way. + + <scons_output example="EnsureSConsVersion"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + SCons 1.0 or greater required, but you have SCons 0.98.5 + </screen> + + </section> + + <section> + <title>Explicitly Terminating &SCons; While Reading &SConscript; Files: the &Exit; Function</title> + + <para> + + &SCons; supports an &Exit; function + which can be used to terminate &SCons; + while reading the &SConscript; files, + usually because you've detected a condition + under which it doesn't make sense to proceed: + + </para> + + <programlisting> + if ARGUMENTS.get('FUTURE'): + print "The FUTURE option is not supported yet!" + Exit(2) + env = Environment() + env.Program('hello.c') + </programlisting> + + <screen> + % <userinput>scons -Q FUTURE=1</userinput> + The FUTURE option is not supported yet! + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + <para> + + The &Exit; function takes as an argument + the (numeric) exit status that you want &SCons; to exit with. + If you don't specify a value, + the default is to exit with <literal>0</literal>, + which indicates successful execution. + + </para> + + <para> + + Note that the &Exit; function + is equivalent to calling the Python + <function>sys.exit</function> function + (which the it actually calls), + but because &Exit; is a &SCons; function, + you don't have to import the Python + <literal>sys</literal> module to use it. + + </para> + + </section> + + <section> + <title>Searching for Files: the &FindFile; Function</title> + + <para> + + The &FindFile; function searches for a file in a list of directories. + If there is only one directory, it can be given as a simple string. + The function returns a File node if a matching file exists, + or None if no file is found. + (See the documentation for the &Glob; function for an alternative way + of searching for entries in a directory.) + + </para> + + <programlisting> + # one directory + print FindFile('missing', '.') + t = FindFile('exists', '.') + print t.__class__, t + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + None + SCons.Node.FS.File exists + scons: `.' is up to date. + </screen> + + <programlisting> + # several directories + includes = [ '.', 'include', 'src/include'] + headers = [ 'nonesuch.h', 'config.h', 'private.h', 'dist.h'] + for hdr in headers: + print '%-12s' % ('%s:' % hdr), FindFile(hdr, includes) +</programlisting> + + <screen> + % <userinput>scons -Q</userinput> + nonesuch.h: None + config.h: config.h + private.h: src/include/private.h + dist.h: include/dist.h + scons: `.' is up to date. + </screen> + + <!-- The man page says this should work, but it fails. + <para> + + If the 'file' parameter is a list of files, + a list of File nodes is returned. + + </para> + + <scons_example name="FindFile1c"> + <file name="SConstruct" printme="1"> + # several directories + includes = [ '.', 'include', 'src/include'] + headers = [ 'nonesuch.h', 'config.h', 'private.h', 'dist.h'] + print FindFile(headers, includes) + </file> + <file name="config.h"> + exists + </file> + <directory name="src"></directory> + <directory name="src/include"></directory> + </file> + <file name="src/include/private.h"> + exists + <directory name="include"></directory> + </file> + <file name="include/dist.h"> + exists + </scons_example> + + <scons_output example="FindFile1c" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + --> + + <para> + + If the file exists in more than one directory, + only the first occurrence is returned. + + </para> + + <programlisting> + print FindFile('multiple', ['sub1', 'sub2', 'sub3']) + print FindFile('multiple', ['sub2', 'sub3', 'sub1']) + print FindFile('multiple', ['sub3', 'sub1', 'sub2']) + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + sub1/multiple + sub2/multiple + sub3/multiple + scons: `.' is up to date. + </screen> + + <!-- file may be a list of file names or a single file name. --> + + <para> + + In addition to existing files, &FindFile; will also find derived files + (that is, non-leaf files) that haven't been built yet. + (Leaf files should already exist, or the build will fail!) + + </para> + + <programlisting> + # Neither file exists, so build will fail + Command('derived', 'leaf', 'cat >$TARGET $SOURCE') + print FindFile('leaf', '.') + print FindFile('derived', '.') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + None + derived + scons: *** [derived] Source `leaf' not found, needed by target `derived'. + </screen> + + <programlisting> + # Neither file exists, so build will fail + Command('derived', 'leaf', 'cat >$TARGET $SOURCE') + print FindFile('leaf', '.') + print FindFile('derived', '.') + + # Only 'leaf' exists + Command('derived', 'leaf', 'cat >$TARGET $SOURCE') + print FindFile('leaf', '.') + print FindFile('derived', '.') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + leaf + derived + cat > derived leaf + </screen> + + <para> + + If a source file exists, &FindFile; will correctly return the name + in the build directory. + + </para> + + <programlisting> + # Only 'src/leaf' exists + VariantDir('build', 'src') + print FindFile('leaf', 'build') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + build/leaf + scons: `.' is up to date. + </screen> + + </section> + + <section> + <title>Handling Nested Lists: the &Flatten; Function</title> + + <para> + + &SCons; supports a &Flatten; function + which takes an input Python sequence + (list or tuple) + and returns a flattened list + containing just the individual elements of + the sequence. + This can be handy when trying to examine + a list composed of the lists + returned by calls to various Builders. + For example, you might collect + object files built in different ways + into one call to the &Program; Builder + by just enclosing them in a list, as follows: + + </para> + + <programlisting> + objects = [ + Object('prog1.c'), + Object('prog2.c', CCFLAGS='-DFOO'), + ] + Program(objects) + </programlisting> + + <para> + + Because the Builder calls in &SCons; + flatten their input lists, + this works just fine to build the program: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o prog1.o -c prog1.c + cc -o prog2.o -c -DFOO prog2.c + cc -o prog1 prog1.o prog2.o + </screen> + + <para> + + But if you were debugging your build + and wanted to print the absolute path + of each object file in the + <varname>objects</varname> list, + you might try the following simple approach, + trying to print each Node's + <literal>abspath</literal> + attribute: + + </para> + + <programlisting> + objects = [ + Object('prog1.c'), + Object('prog2.c', CCFLAGS='-DFOO'), + ] + Program(objects) + + for object_file in objects: + print object_file.abspath + </programlisting> + + <para> + + This does not work as expected + because each call to <function>str</function> + is operating an embedded list returned by + each &Object; call, + not on the underlying Nodes within those lists: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + AttributeError: NodeList instance has no attribute 'abspath': + File "/home/my/project/SConstruct", line 8: + print object_file.abspath + </screen> + + <para> + + The solution is to use the &Flatten; function + so that you can pass each Node to + the <function>str</function> separately: + + </para> + + <programlisting> + objects = [ + Object('prog1.c'), + Object('prog2.c', CCFLAGS='-DFOO'), + ] + Program(objects) + + for object_file in Flatten(objects): + print object_file.abspath + </programlisting> + + <!-- + + TODO: can't use this now because it displays the temporary path name + + <scons_output example="Flatten3"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + /home/me/project/prog1.o + /home/me/project/prog2.o + cc -o prog1.o -c prog1.c + cc -o prog2.o -c -DFOO prog2.c + cc -o prog1 prog1.o prog2.o + </screen> + + </section> + + <section> + <title>Finding the Invocation Directory: the &GetLaunchDir; Function</title> + + <para> + + If you need to find the directory from + which the user invoked the &scons; command, + you can use the &GetLaunchDir; function: + + </para> + + <programlisting> + env = Environment( + LAUNCHDIR = GetLaunchDir(), + ) + env.Command('directory_build_info', + '$LAUNCHDIR/build_info' + Copy('$TARGET', '$SOURCE')) + </programlisting> + + <para> + + Because &SCons; is usually invoked from the top-level + directory in which the &SConstruct; file lives, + the Python <function>os.getcwd()</function> + is often equivalent. + However, the &SCons; + <literal>-u</literal>, + <literal>-U</literal> + and + <literal>-D</literal> + command-line options, + when invoked from a subdirectory, + will cause &SCons; to change to the directory + in which the &SConstruct; file is found. + When those options are used, + &GetLaunchDir; will still return the path to the + user's invoking subdirectory, + allowing the &SConscript; configuration + to still get at configuration (or other) files + from the originating directory. + + </para> + + </section> diff --git a/doc/user/nodes.in b/doc/user/nodes.in new file mode 100644 index 0000000..c914ce5 --- /dev/null +++ b/doc/user/nodes.in @@ -0,0 +1,386 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + Internally, &SCons; represents all of the files + and directories it knows about as &Nodes;. + These internal objects + (not object <emphasis>files</emphasis>) + can be used in a variety of ways + to make your &SConscript; + files portable and easy to read. + + </para> + + <section> + <title>Builder Methods Return Lists of Target Nodes</title> + + <para> + + All builder methods return a list of + &Node; objects that identify the + target file or files that will be built. + These returned &Nodes; can be passed + as arguments to other builder methods. + + </para> + + <para> + + For example, suppose that we want to build + the two object files that make up a program with different options. + This would mean calling the &b-link-Object; + builder once for each object file, + specifying the desired options: + + </para> + + <sconstruct> + Object('hello.c', CCFLAGS='-DHELLO') + Object('goodbye.c', CCFLAGS='-DGOODBYE') + </sconstruct> + + <para> + + One way to combine these object files + into the resulting program + would be to call the &b-link-Program; + builder with the names of the object files + listed as sources: + + </para> + + <sconstruct> + Object('hello.c', CCFLAGS='-DHELLO') + Object('goodbye.c', CCFLAGS='-DGOODBYE') + Program(['hello.o', 'goodbye.o']) + </sconstruct> + + <para> + + The problem with specifying the names as strings + is that our &SConstruct; file is no longer portable + across operating systems. + It won't, for example, work on Windows + because the object files there would be + named &hello_obj; and &goodbye_obj;, + not &hello_o; and &goodbye_o;. + + </para> + + <para> + + A better solution is to assign the lists of targets + returned by the calls to the &b-Object; builder to variables, + which we can then concatenate in our + call to the &b-Program; builder: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + hello_list = Object('hello.c', CCFLAGS='-DHELLO') + goodbye_list = Object('goodbye.c', CCFLAGS='-DGOODBYE') + Program(hello_list + goodbye_list) + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + <file name="goodbye.c"> + int main() { printf("Goodbye, world!\n"); } + </file> + </scons_example> + + <para> + + This makes our &SConstruct; file portable again, + the build output on Linux looking like: + + </para> + + <scons_output example="ex1" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + And on Windows: + + </para> + + <scons_output example="ex1" os="win32"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + We'll see examples of using the list of nodes + returned by builder methods throughout + the rest of this guide. + + </para> + + </section> + + <section> + <title>Explicitly Creating File and Directory Nodes</title> + + <para> + + It's worth mentioning here that + &SCons; maintains a clear distinction + between Nodes that represent files + and Nodes that represent directories. + &SCons; supports &File; and &Dir; + functions that, respectively, + return a file or directory Node: + + </para> + + <scons_example name="print"> + <file name="SConstruct" printme="1"> + hello_c = File('hello.c') + Program(hello_c) + + classes = Dir('classes') + Java(classes, 'src') + </file> + </scons_example> + + <para> + + Normally, you don't need to call + &File; or &Dir; directly, + because calling a builder method automatically + treats strings as the names of files or directories, + and translates them into + the Node objects for you. + The &File; and &Dir; functions can come in handy + in situations where you need to explicitly + instruct &SCons; about the type of Node being + passed to a builder or other function, + or unambiguously refer to a specific + file in a directory tree. + <!-- + (For an example of when you might + need to use &File; or &Dir; to + prevent ambiguous interpretation of a string + naming a file or directory, see + <xref linkend="chap-hierarchy">.) + --> + + </para> + + <para> + + There are also times when you may need to + refer to an entry in a file system + without knowing in advance + whether it's a file or a directory. + For those situations, + &SCons; also supports an &Entry; function, + which returns a Node + that can represent either a file or a directory. + + </para> + + <sconstruct> + xyzzy = Entry('xyzzy') + </sconstruct> + + <para> + + The returned <literal>xyzzy</literal> Node + will be turned into a file or directory Node + the first time it is used by a builder method + or other function that + requires one vs. the other. + + </para> + + </section> + + <section> + <title>Printing &Node; File Names</title> + + <para> + + One of the most common things you can do + with a Node is use it to print the + file name that the node represents. + Keep in mind, though, that because the object + returned by a builder call + is a <emphasis>list</emphasis> of Nodes, + you must use Python subscripts + to fetch individual Nodes from the list. + For example, the following &SConstruct; file: + + </para> + + <scons_example name="print"> + <file name="SConstruct" printme="1"> + object_list = Object('hello.c') + program_list = Program(object_list) + print "The object file is:", object_list[0] + print "The program file is:", program_list[0] + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + Would print the following file names on a POSIX system: + + </para> + + <scons_output example="print" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + And the following file names on a Windows system: + + </para> + + <scons_output example="print" os="win32"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Note that in the above example, + the <literal>object_list[0]</literal> + extracts an actual Node <emphasis>object</emphasis> + from the list, + and the Python <literal>print</literal> statement + converts the object to a string for printing. + + </para> + + </section> + + <section> + <title>Using a &Node;'s File Name as a String</title> + + <para> + + Printing a &Node;'s name + as described in the previous section + works because the string representation of a &Node; object + is the name of the file. + If you want to do something other than + print the name of the file, + you can fetch it by using the builtin Python + &str; function. + For example, if you want to use the Python + <function>os.path.exists</function> + to figure out whether a file + exists while the &SConstruct; file + is being read and executed, + you can fetch the string as follows: + + </para> + + <scons_example name="exists"> + <file name="SConstruct" printme="1"> + import os.path + program_list = Program('hello.c') + program_name = str(program_list[0]) + if not os.path.exists(program_name): + print program_name, "does not exist!" + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + Which executes as follows on a POSIX system: + + </para> + + <scons_output example="exists" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <!-- + + <section> + <title>Fetching the Contents of a &Node;</title> + + <para> + + XXX Describe using read() and readlines() + when we add that as a public interface. + + </para> + + <scons_example name="read"> + <file name="SConstruct" printme="1"> + hello_c = File('hello.c') + contents = hello_c.read() + print "contents are:" + print contents + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + Which executes as follows on a POSIX system: + + </para> + + <scons_output example="read" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + --> + + <!-- + + <section> + <title>Python Value &Node;</title> + + <para> + + XXX Value() + + </para> + + </section> + + --> diff --git a/doc/user/nodes.xml b/doc/user/nodes.xml new file mode 100644 index 0000000..46215c4 --- /dev/null +++ b/doc/user/nodes.xml @@ -0,0 +1,401 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + Internally, &SCons; represents all of the files + and directories it knows about as &Nodes;. + These internal objects + (not object <emphasis>files</emphasis>) + can be used in a variety of ways + to make your &SConscript; + files portable and easy to read. + + </para> + + <section> + <title>Builder Methods Return Lists of Target Nodes</title> + + <para> + + All builder methods return a list of + &Node; objects that identify the + target file or files that will be built. + These returned &Nodes; can be passed + as arguments to other builder methods. + + </para> + + <para> + + For example, suppose that we want to build + the two object files that make up a program with different options. + This would mean calling the &b-link-Object; + builder once for each object file, + specifying the desired options: + + </para> + + <programlisting> + Object('hello.c', CCFLAGS='-DHELLO') + Object('goodbye.c', CCFLAGS='-DGOODBYE') + </programlisting> + + <para> + + One way to combine these object files + into the resulting program + would be to call the &b-link-Program; + builder with the names of the object files + listed as sources: + + </para> + + <programlisting> + Object('hello.c', CCFLAGS='-DHELLO') + Object('goodbye.c', CCFLAGS='-DGOODBYE') + Program(['hello.o', 'goodbye.o']) + </programlisting> + + <para> + + The problem with specifying the names as strings + is that our &SConstruct; file is no longer portable + across operating systems. + It won't, for example, work on Windows + because the object files there would be + named &hello_obj; and &goodbye_obj;, + not &hello_o; and &goodbye_o;. + + </para> + + <para> + + A better solution is to assign the lists of targets + returned by the calls to the &b-Object; builder to variables, + which we can then concatenate in our + call to the &b-Program; builder: + + </para> + + <programlisting> + hello_list = Object('hello.c', CCFLAGS='-DHELLO') + goodbye_list = Object('goodbye.c', CCFLAGS='-DGOODBYE') + Program(hello_list + goodbye_list) + </programlisting> + + <para> + + This makes our &SConstruct; file portable again, + the build output on Linux looking like: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o goodbye.o -c -DGOODBYE goodbye.c + cc -o hello.o -c -DHELLO hello.c + cc -o hello hello.o goodbye.o + </screen> + + <para> + + And on Windows: + + </para> + + <screen> + C:\><userinput>scons -Q</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + cl /Fogoodbye.obj /c goodbye.c -DGOODBYE + cl /Fohello.obj /c hello.c -DHELLO + link /nologo /OUT:hello.exe hello.obj goodbye.obj + </screen> + + <para> + + We'll see examples of using the list of nodes + returned by builder methods throughout + the rest of this guide. + + </para> + + </section> + + <section> + <title>Explicitly Creating File and Directory Nodes</title> + + <para> + + It's worth mentioning here that + &SCons; maintains a clear distinction + between Nodes that represent files + and Nodes that represent directories. + &SCons; supports &File; and &Dir; + functions that, respectively, + return a file or directory Node: + + </para> + + <programlisting> + hello_c = File('hello.c') + Program(hello_c) + + classes = Dir('classes') + Java(classes, 'src') + </programlisting> + + <para> + + Normally, you don't need to call + &File; or &Dir; directly, + because calling a builder method automatically + treats strings as the names of files or directories, + and translates them into + the Node objects for you. + The &File; and &Dir; functions can come in handy + in situations where you need to explicitly + instruct &SCons; about the type of Node being + passed to a builder or other function, + or unambiguously refer to a specific + file in a directory tree. + <!-- + (For an example of when you might + need to use &File; or &Dir; to + prevent ambiguous interpretation of a string + naming a file or directory, see + <xref linkend="chap-hierarchy">.) + --> + + </para> + + <para> + + There are also times when you may need to + refer to an entry in a file system + without knowing in advance + whether it's a file or a directory. + For those situations, + &SCons; also supports an &Entry; function, + which returns a Node + that can represent either a file or a directory. + + </para> + + <programlisting> + xyzzy = Entry('xyzzy') + </programlisting> + + <para> + + The returned <literal>xyzzy</literal> Node + will be turned into a file or directory Node + the first time it is used by a builder method + or other function that + requires one vs. the other. + + </para> + + </section> + + <section> + <title>Printing &Node; File Names</title> + + <para> + + One of the most common things you can do + with a Node is use it to print the + file name that the node represents. + Keep in mind, though, that because the object + returned by a builder call + is a <emphasis>list</emphasis> of Nodes, + you must use Python subscripts + to fetch individual Nodes from the list. + For example, the following &SConstruct; file: + + </para> + + <programlisting> + hello_c = File('hello.c') + Program(hello_c) + + classes = Dir('classes') + Java(classes, 'src') + + object_list = Object('hello.c') + program_list = Program(object_list) + print "The object file is:", object_list[0] + print "The program file is:", program_list[0] + </programlisting> + + <para> + + Would print the following file names on a POSIX system: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + The object file is: hello.o + The program file is: hello + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + <para> + + And the following file names on a Windows system: + + </para> + + <screen> + C:\><userinput>scons -Q</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + The object file is: hello.obj + The program file is: hello.exe + cl /Fohello.obj /c hello.c /nologo + link /nologo /OUT:hello.exe hello.obj + </screen> + + <para> + + Note that in the above example, + the <literal>object_list[0]</literal> + extracts an actual Node <emphasis>object</emphasis> + from the list, + and the Python <literal>print</literal> statement + converts the object to a string for printing. + + </para> + + </section> + + <section> + <title>Using a &Node;'s File Name as a String</title> + + <para> + + Printing a &Node;'s name + as described in the previous section + works because the string representation of a &Node; object + is the name of the file. + If you want to do something other than + print the name of the file, + you can fetch it by using the builtin Python + &str; function. + For example, if you want to use the Python + <function>os.path.exists</function> + to figure out whether a file + exists while the &SConstruct; file + is being read and executed, + you can fetch the string as follows: + + </para> + + <programlisting> + import os.path + program_list = Program('hello.c') + program_name = str(program_list[0]) + if not os.path.exists(program_name): + print program_name, "does not exist!" + </programlisting> + + <para> + + Which executes as follows on a POSIX system: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + hello does not exist! + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + </section> + + <!-- + + <section> + <title>Fetching the Contents of a &Node;</title> + + <para> + + XXX Describe using read() and readlines() + when we add that as a public interface. + + </para> + + <scons_example name="read"> + <file name="SConstruct" printme="1"> + hello_c = File('hello.c') + contents = hello_c.read() + print "contents are:" + print contents + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + Which executes as follows on a POSIX system: + + </para> + + <scons_output example="read" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + --> + + <!-- + + <section> + <title>Python Value &Node;</title> + + <para> + + XXX Value() + + </para> + + </section> + + --> diff --git a/doc/user/output.in b/doc/user/output.in new file mode 100644 index 0000000..1f600f3 --- /dev/null +++ b/doc/user/output.in @@ -0,0 +1,681 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + A key aspect of creating a usable build configuration + is providing good output from the build + so its users can readily understand + what the build is doing + and get information about how to control the build. + &SCons; provides several ways of + controlling output from the build configuration + to help make the build + more useful and understandable. + + </para> + + <section> + <title>Providing Build Help: the &Help; Function</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 your build. + &SCons; provides the &Help; function + to allow you to specify this help text: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + Help(""" + Type: 'scons program' to build the production program, + 'scons debug' to build the debug version. + """) + </file> + </scons_example> + + <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> + + <scons_output example="ex1"> + <scons_output_command>scons -h</scons_output_command> + </scons_output> + + <para> + + The &SConscript; files may contain + multiple calls to the &Help; function, + in which case the specified text(s) + will be concatenated when displayed. + This allows you to split up the + help text across multiple &SConscript; files. + In this situation, the order in + which the &SConscript; files are called + will determine the order in which the &Help; functions are called, + which will determine the order in which + the various bits of text will get concatenated. + + </para> + + <para> + + Another use would be to make the help text conditional + on some variable. + For example, suppose you only want to display + a line about building a Windows-only + version of a program when actually + run on Windows. + The following &SConstruct; file: + + </para> + + <scons_example name="ex2"> + <file name="SConstruct" printme="1"> + env = Environment() + + Help("\nType: 'scons program' to build the production program.\n") + + if env['PLATFORM'] == 'win32': + Help("\nType: 'scons windebug' to build the Windows debug version.\n") + </file> + </scons_example> + + <para> + + Will display the complete help text on Windows: + + </para> + + <scons_output example="ex2" os="win32"> + <scons_output_command>scons -h</scons_output_command> + </scons_output> + + <para> + + But only show the relevant option on a Linux or UNIX system: + + </para> + + <scons_output example="ex2" os="posix"> + <scons_output_command>scons -h</scons_output_command> + </scons_output> + + <para> + + If there is no &Help; text in the &SConstruct; or + &SConscript; files, + &SCons; will revert to displaying its + standard list that describes the &SCons; command-line + options. + This list is also always displayed whenever + the <literal>-H</literal> option is used. + + </para> + + </section> + + <section> + <title>Controlling How &SCons; Prints Build Commands: the <envar>$*COMSTR</envar> Variables</title> + + <para> + + Sometimes the commands executed + to compile object files or link programs + (or build other targets) + can get very long, + long enough to make it difficult for users + to distinguish error messages or + other important build output + from the commands themselves. + All of the default <envar>$*COM</envar> variables + that specify the command lines + used to build various types of target files + have a corresponding <envar>$*COMSTR</envar> variable + that can be set to an alternative + string that will be displayed + when the target is built. + + </para> + + <para> + + For example, suppose you want to + have &SCons; display a + <literal>"Compiling"</literal> + message whenever it's compiling an object file, + and a + <literal>"Linking"</literal> + when it's linking an executable. + You could write a &SConstruct; file + that looks like: + + </para> + + <scons_example name="COMSTR"> + <file name="SConstruct" printme="1"> + env = Environment(CCCOMSTR = "Compiling $TARGET", + LINKCOMSTR = "Linking $TARGET") + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + </scons_example> + + <para> + + Which would then yield the output: + + </para> + + <!-- + + <scons_output example="COMSTR" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + Compiling foo.o + Linking foo + </screen> + + <para> + + &SCons; performs complete variable substitution + on <envar>$*COMSTR</envar> variables, + so they have access to all of the + standard variables like &cv-TARGET; &cv-SOURCES;, etc., + as well as any construction variables + that happen to be configured in + the construction environment + used to build a specific target. + + </para> + + <para> + + Of course, sometimes it's still important to + be able to see the exact command + that &SCons; will execute to build a target. + For example, you may simply need to verify + that &SCons; is configured to supply + the right options to the compiler, + or a developer may want to + cut-and-paste a compile command + to add a few options + for a custom test. + + </para> + + <para> + + One common way to give users + control over whether or not + &SCons; should print the actual command line + or a short, configured summary + is to add support for a + <varname>VERBOSE</varname> + command-line variable to your &SConstruct; file. + A simple configuration for this might look like: + + </para> + + <scons_example name="COMSTR-VERBOSE"> + <file name="SConstruct" printme="1"> + env = Environment() + if ARGUMENTS.get('VERBOSE') != "1': + env['CCCOMSTR'] = "Compiling $TARGET" + env['LINKCOMSTR'] = "Linking $TARGET" + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + </scons_example> + + <para> + + + By only setting the appropriate + <envar>$*COMSTR</envar> variables + if the user specifies + <literal>VERBOSE=1</literal> + on the command line, + the user has control + over how &SCons; + displays these particular command lines: + + </para> + + <!-- + + <scons_output example="COMSTR-VERBOSE" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q -c</scons_output_command> + <scons_output_command>scons -Q VERBOSE=1</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + Compiling foo.o + Linking foo + % <userinput>scons -Q -c</userinput> + Removed foo.o + Removed foo + % <userinput>scons -Q VERBOSE=1</userinput> + cc -o foo.o -c foo.c + cc -o foo foo.o + </screen> + + </section> + + <section> + <title>Providing Build Progress Output: the &Progress; Function</title> + + <para> + + Another aspect of providing good build output + is to give the user feedback + about what &SCons; is doing + even when nothing is being built at the moment. + This can be especially true for large builds + when most of the targets are already up-to-date. + Because &SCons; can take a long time + making absolutely sure that every + target is, in fact, up-to-date + with respect to a lot of dependency files, + it can be easy for users to mistakenly + conclude that &SCons; is hung + or that there is some other problem with the build. + + </para> + + <para> + + One way to deal with this perception + is to configure &SCons; to print something to + let the user know what it's "thinking about." + The &Progress; function + allows you to specify a string + that will be printed for every file + that &SCons; is "considering" + while it is traversing the dependency graph + to decide what targets are or are not up-to-date. + + </para> + + <scons_example name="Progress-TARGET"> + <file name="SConstruct" printme="1"> + Progress('Evaluating $TARGET\n') + Program('f1.c') + Program('f2.c') + </file> + <file name="f1.c"> + f1.c + </file> + <file name="f2.c"> + f2.c + </file> + </scons_example> + + <para> + + Note that the &Progress; function does not + arrange for a newline to be printed automatically + at the end of the string (as does the Python + <literal>print</literal> statement), + and we must specify the + <literal>\n</literal> + that we want printed at the end of the configured string. + This configuration, then, + will have &SCons; + print that it is <literal>Evaluating</literal> + each file that it encounters + in turn as it traverses the dependency graph: + + </para> + + <scons_output example="Progress-TARGET" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Of course, normally you don't want to add + all of these additional lines to your build output, + as that can make it difficult for the user + to find errors or other important messages. + A more useful way to display + this progress might be + to have the file names printed + directly to the user's screen, + not to the same standard output + stream where build output is printed, + and to use a carriage return character + (<literal>\r</literal>) + so that each file name gets re-printed on the same line. + Such a configuration would look like: + + </para> + + <sconstruct> + Progress('$TARGET\r', + file=open('/dev/tty', 'w'), + overwrite=True) + Program('f1.c') + Program('f2.c') + </sconstruct> + + <para> + + Note that we also specified the + <literal>overwrite=True</literal> argument + to the &Progress; function, + which causes &SCons; to + "wipe out" the previous string with space characters + before printing the next &Progress; string. + Without the + <literal>overwrite=True</literal> argument, + a shorter file name would not overwrite + all of the charactes in a longer file name that + precedes it, + making it difficult to tell what the + actual file name is on the output. + Also note that we opened up the + <filename>/dev/tty</filename> file + for direct access (on POSIX) to + the user's screen. + On Windows, the equivalent would be to open + the <filename>con:</filename> file name. + + </para> + + <para> + + Also, it's important to know that although you can use + <literal>$TARGET</literal> to substitute the name of + the node in the string, + the &Progress; function does <emphasis>not</emphasis> + perform general variable substitution + (because there's not necessarily a construction + environment involved in evaluating a node + like a source file, for example). + + </para> + + <para> + + You can also specify a list of strings + to the &Progress; function, + in which case &SCons; will + display each string in turn. + This can be used to implement a "spinner" + by having &SCons; cycle through a + sequence of strings: + + </para> + + <sconstruct> + Progress(['-\r', '\\\r', '|\r', '/\r'], interval=5) + Program('f1.c') + Program('f2.c') + </sconstruct> + + <para> + + Note that here we have also used the + <literal>interval=</literal> + keyword argument to have &SCons; + only print a new "spinner" string + once every five evaluated nodes. + Using an <literal>interval=</literal> count, + even with strings that use <literal>$TARGET</literal> like + our examples above, + can be a good way to lessen the + work that &SCons; expends printing &Progress; strings, + while still giving the user feedback + that indicates &SCons; is still + working on evaluating the build. + + </para> + + <para> + + Lastly, you can have direct control + over how to print each evaluated node + by passing a Python function + (or other Python callable) + to the &Progress function. + Your function will be called + for each evaluated node, + allowing you to + implement more sophisticated logic + like adding a counter: + + </para> + + <scons_example name="Progress-callable"> + <file name="SConstruct" printme="1"> + screen = open('/dev/tty', 'w') + count = 0 + def progress_function(node) + count += 1 + screen.write('Node %4d: %s\r' % (count, node)) + + Progress(progress_function) + </file> + </scons_example> + + <para> + + Of course, if you choose, + you could completely ignore the + <varname>node</varname> argument to the function, + and just print a count, + or anything else you wish. + + </para> + + <para> + + (Note that there's an obvious follow-on question here: + how would you find the total number of nodes + that <emphasis>will be</emphasis> + evaluated so you can tell the user how + close the build is to finishing? + Unfortunately, in the general case, + there isn't a good way to do that, + short of having &SCons; evaluate its + dependency graph twice, + first to count the total and + the second time to actually build the targets. + This would be necessary because + you can't know in advance which + target(s) the user actually requested + to be built. + The entire build may consist of thousands of Nodes, + for example, + but maybe the user specifically requested + that only a single object file be built.) + + </para> + + </section> + + <section> + <title>Printing Detailed Build Status: the &GetBuildFailures; Function</title> + + <para> + + SCons, like most build tools, returns zero status to + the shell on success and nonzero status on failure. + Sometimes it's useful to give more information about + the build status at the end of the run, for instance + to print an informative message, send an email, or + page the poor slob who broke the build. + + </para> + + <para> + + SCons provides a &GetBuildFailures; method that + you can use in a python <function>atexit</function> function + to get a list of objects describing the actions that failed + while attempting to build targets. There can be more + than one if you're using <literal>-j</literal>. Here's a + simple example: + + </para> + + <scons_example name="gbf1"> + <file name="SConstruct" printme="1"> + import atexit + + def print_build_failures(): + from SCons.Script import GetBuildFailures + for bf in GetBuildFailures(): + print "%s failed: %s" % (bf.node, bf.errstr) + atexit.register(print_build_failures) + </file> + </scons_example> + + <para> + + The <function>atexit.register</function> call + registers <function>print_build_failures</function> + as an <function>atexit</function> callback, to be called + before &SCons; exits. When that function is called, + it calls &GetBuildFailures; to fetch the list of failed objects. + See the man page + for the detailed contents of the returned objects; + some of the more useful attributes are + <literal>.node</literal>, + <literal>.errstr</literal>, + <literal>.filename</literal>, and + <literal>.command</literal>. + The <literal>filename</literal> is not necessarily + the same file as the <literal>node</literal>; the + <literal>node</literal> is the target that was + being built when the error occurred, while the + <literal>filename</literal>is the file or dir that + actually caused the error. + Note: only call &GetBuildFailures; at the end of the + build; calling it at any other time is undefined. + + </para> + + <para> + + Here is a more complete example showing how to + turn each element of &GetBuildFailures; into a string: + + </para> + + <scons_example name="gbf2"> + <file name="SConstruct" printme="1"> + # Make the build fail if we pass fail=1 on the command line + if ARGUMENTS.get('fail', 0): + Command('target', 'source', ['/bin/false']) + + def bf_to_str(bf): + """Convert an element of GetBuildFailures() to a string + in a useful way.""" + import SCons.Errors + if bf is None: # unknown targets product None in list + return '(unknown tgt)' + elif isinstance(bf, SCons.Errors.StopError): + return str(bf) + elif bf.node: + return str(bf.node) + ': ' + bf.errstr + elif bf.filename: + return bf.filename + ': ' + bf.errstr + return 'unknown failure: ' + bf.errstr + import atexit + + def build_status(): + """Convert the build status to a 2-tuple, (status, msg).""" + from SCons.Script import GetBuildFailures + bf = GetBuildFailures() + if bf: + # bf is normally a list of build failures; if an element is None, + # it's because of a target that scons doesn't know anything about. + status = 'failed' + failures_message = "\n".join(["Failed building %s" % bf_to_str(x) + for x in bf if x is not None]) + else: + # if bf is None, the build completed successfully. + status = 'ok' + failures_message = '' + return (status, failures_message) + + def display_build_status(): + """Display the build status. Called by atexit. + Here you could do all kinds of complicated things.""" + status, failures_message = build_status() + if status == 'failed': + print "FAILED!!!!" # could display alert, ring bell, etc. + elif status == 'ok': + print "Build succeeded." + print failures_message + + atexit.register(display_build_status) + </file> + </scons_example> + + <para> + + When this runs, you'll see the appropriate output: + + </para> + + <scons_output example="gbf2"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q fail=1</scons_output_command> + </scons_output> + + </section> diff --git a/doc/user/output.xml b/doc/user/output.xml new file mode 100644 index 0000000..89b443b --- /dev/null +++ b/doc/user/output.xml @@ -0,0 +1,703 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + A key aspect of creating a usable build configuration + is providing good output from the build + so its users can readily understand + what the build is doing + and get information about how to control the build. + &SCons; provides several ways of + controlling output from the build configuration + to help make the build + more useful and understandable. + + </para> + + <section> + <title>Providing Build Help: the &Help; Function</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 your 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> + + <screen> + % <userinput>scons -h</userinput> + scons: Reading SConscript files ... + scons: done reading SConscript files. + + Type: 'scons program' to build the production program, + 'scons debug' to build the debug version. + + Use scons -H for help about command-line options. + </screen> + + <para> + + The &SConscript; files may contain + multiple calls to the &Help; function, + in which case the specified text(s) + will be concatenated when displayed. + This allows you to split up the + help text across multiple &SConscript; files. + In this situation, the order in + which the &SConscript; files are called + will determine the order in which the &Help; functions are called, + which will determine the order in which + the various bits of text will get concatenated. + + </para> + + <para> + + Another use would be to make the help text conditional + on some variable. + For example, suppose you only want to display + a line about building a Windows-only + version of a program when actually + run on Windows. + The following &SConstruct; file: + + </para> + + <programlisting> + env = Environment() + + Help("\nType: 'scons program' to build the production program.\n") + + if env['PLATFORM'] == 'win32': + Help("\nType: 'scons windebug' to build the Windows debug version.\n") + </programlisting> + + <para> + + Will display the complete help text on Windows: + + </para> + + <screen> + C:\><userinput>scons -h</userinput> + scons: Reading SConscript files ... + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + scons: done reading SConscript files. + + Type: 'scons program' to build the production program. + + Type: 'scons windebug' to build the Windows debug version. + + Use scons -H for help about command-line options. + </screen> + + <para> + + But only show the relevant option on a Linux or UNIX system: + + </para> + + <screen> + % <userinput>scons -h</userinput> + scons: Reading SConscript files ... + scons: done reading SConscript files. + + Type: 'scons program' to build the production program. + + Use scons -H for help about command-line options. + </screen> + + <para> + + If there is no &Help; text in the &SConstruct; or + &SConscript; files, + &SCons; will revert to displaying its + standard list that describes the &SCons; command-line + options. + This list is also always displayed whenever + the <literal>-H</literal> option is used. + + </para> + + </section> + + <section> + <title>Controlling How &SCons; Prints Build Commands: the <envar>$*COMSTR</envar> Variables</title> + + <para> + + Sometimes the commands executed + to compile object files or link programs + (or build other targets) + can get very long, + long enough to make it difficult for users + to distinguish error messages or + other important build output + from the commands themselves. + All of the default <envar>$*COM</envar> variables + that specify the command lines + used to build various types of target files + have a corresponding <envar>$*COMSTR</envar> variable + that can be set to an alternative + string that will be displayed + when the target is built. + + </para> + + <para> + + For example, suppose you want to + have &SCons; display a + <literal>"Compiling"</literal> + message whenever it's compiling an object file, + and a + <literal>"Linking"</literal> + when it's linking an executable. + You could write a &SConstruct; file + that looks like: + + </para> + + <programlisting> + env = Environment(CCCOMSTR = "Compiling $TARGET", + LINKCOMSTR = "Linking $TARGET") + env.Program('foo.c') + </programlisting> + + <para> + + Which would then yield the output: + + </para> + + <!-- + + <scons_output example="COMSTR" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + Compiling foo.o + Linking foo + </screen> + + <para> + + &SCons; performs complete variable substitution + on <envar>$*COMSTR</envar> variables, + so they have access to all of the + standard variables like &cv-TARGET; &cv-SOURCES;, etc., + as well as any construction variables + that happen to be configured in + the construction environment + used to build a specific target. + + </para> + + <para> + + Of course, sometimes it's still important to + be able to see the exact command + that &SCons; will execute to build a target. + For example, you may simply need to verify + that &SCons; is configured to supply + the right options to the compiler, + or a developer may want to + cut-and-paste a compile command + to add a few options + for a custom test. + + </para> + + <para> + + One common way to give users + control over whether or not + &SCons; should print the actual command line + or a short, configured summary + is to add support for a + <varname>VERBOSE</varname> + command-line variable to your &SConstruct; file. + A simple configuration for this might look like: + + </para> + + <programlisting> + env = Environment() + if ARGUMENTS.get('VERBOSE') != "1': + env['CCCOMSTR'] = "Compiling $TARGET" + env['LINKCOMSTR'] = "Linking $TARGET" + env.Program('foo.c') + </programlisting> + + <para> + + + By only setting the appropriate + <envar>$*COMSTR</envar> variables + if the user specifies + <literal>VERBOSE=1</literal> + on the command line, + the user has control + over how &SCons; + displays these particular command lines: + + </para> + + <!-- + + <scons_output example="COMSTR-VERBOSE" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q -c</scons_output_command> + <scons_output_command>scons -Q VERBOSE=1</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + Compiling foo.o + Linking foo + % <userinput>scons -Q -c</userinput> + Removed foo.o + Removed foo + % <userinput>scons -Q VERBOSE=1</userinput> + cc -o foo.o -c foo.c + cc -o foo foo.o + </screen> + + </section> + + <section> + <title>Providing Build Progress Output: the &Progress; Function</title> + + <para> + + Another aspect of providing good build output + is to give the user feedback + about what &SCons; is doing + even when nothing is being built at the moment. + This can be especially true for large builds + when most of the targets are already up-to-date. + Because &SCons; can take a long time + making absolutely sure that every + target is, in fact, up-to-date + with respect to a lot of dependency files, + it can be easy for users to mistakenly + conclude that &SCons; is hung + or that there is some other problem with the build. + + </para> + + <para> + + One way to deal with this perception + is to configure &SCons; to print something to + let the user know what it's "thinking about." + The &Progress; function + allows you to specify a string + that will be printed for every file + that &SCons; is "considering" + while it is traversing the dependency graph + to decide what targets are or are not up-to-date. + + </para> + + <programlisting> + Progress('Evaluating $TARGET\n') + Program('f1.c') + Program('f2.c') + </programlisting> + + <para> + + Note that the &Progress; function does not + arrange for a newline to be printed automatically + at the end of the string (as does the Python + <literal>print</literal> statement), + and we must specify the + <literal>\n</literal> + that we want printed at the end of the configured string. + This configuration, then, + will have &SCons; + print that it is <literal>Evaluating</literal> + each file that it encounters + in turn as it traverses the dependency graph: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + Evaluating SConstruct + Evaluating f1.c + Evaluating f1.o + cc -o f1.o -c f1.c + Evaluating f1 + cc -o f1 f1.o + Evaluating f2.c + Evaluating f2.o + cc -o f2.o -c f2.c + Evaluating f2 + cc -o f2 f2.o + Evaluating . + </screen> + + <para> + + Of course, normally you don't want to add + all of these additional lines to your build output, + as that can make it difficult for the user + to find errors or other important messages. + A more useful way to display + this progress might be + to have the file names printed + directly to the user's screen, + not to the same standard output + stream where build output is printed, + and to use a carriage return character + (<literal>\r</literal>) + so that each file name gets re-printed on the same line. + Such a configuration would look like: + + </para> + + <programlisting> + Progress('$TARGET\r', + file=open('/dev/tty', 'w'), + overwrite=True) + Program('f1.c') + Program('f2.c') + </programlisting> + + <para> + + Note that we also specified the + <literal>overwrite=True</literal> argument + to the &Progress; function, + which causes &SCons; to + "wipe out" the previous string with space characters + before printing the next &Progress; string. + Without the + <literal>overwrite=True</literal> argument, + a shorter file name would not overwrite + all of the charactes in a longer file name that + precedes it, + making it difficult to tell what the + actual file name is on the output. + Also note that we opened up the + <filename>/dev/tty</filename> file + for direct access (on POSIX) to + the user's screen. + On Windows, the equivalent would be to open + the <filename>con:</filename> file name. + + </para> + + <para> + + Also, it's important to know that although you can use + <literal>$TARGET</literal> to substitute the name of + the node in the string, + the &Progress; function does <emphasis>not</emphasis> + perform general variable substitution + (because there's not necessarily a construction + environment involved in evaluating a node + like a source file, for example). + + </para> + + <para> + + You can also specify a list of strings + to the &Progress; function, + in which case &SCons; will + display each string in turn. + This can be used to implement a "spinner" + by having &SCons; cycle through a + sequence of strings: + + </para> + + <programlisting> + Progress(['-\r', '\\\r', '|\r', '/\r'], interval=5) + Program('f1.c') + Program('f2.c') + </programlisting> + + <para> + + Note that here we have also used the + <literal>interval=</literal> + keyword argument to have &SCons; + only print a new "spinner" string + once every five evaluated nodes. + Using an <literal>interval=</literal> count, + even with strings that use <literal>$TARGET</literal> like + our examples above, + can be a good way to lessen the + work that &SCons; expends printing &Progress; strings, + while still giving the user feedback + that indicates &SCons; is still + working on evaluating the build. + + </para> + + <para> + + Lastly, you can have direct control + over how to print each evaluated node + by passing a Python function + (or other Python callable) + to the &Progress; function. + Your function will be called + for each evaluated node, + allowing you to + implement more sophisticated logic + like adding a counter: + + </para> + + <programlisting> + screen = open('/dev/tty', 'w') + count = 0 + def progress_function(node) + count += 1 + screen.write('Node %4d: %s\r' % (count, node)) + + Progress(progress_function) + </programlisting> + + <para> + + Of course, if you choose, + you could completely ignore the + <varname>node</varname> argument to the function, + and just print a count, + or anything else you wish. + + </para> + + <para> + + (Note that there's an obvious follow-on question here: + how would you find the total number of nodes + that <emphasis>will be</emphasis> + evaluated so you can tell the user how + close the build is to finishing? + Unfortunately, in the general case, + there isn't a good way to do that, + short of having &SCons; evaluate its + dependency graph twice, + first to count the total and + the second time to actually build the targets. + This would be necessary because + you can't know in advance which + target(s) the user actually requested + to be built. + The entire build may consist of thousands of Nodes, + for example, + but maybe the user specifically requested + that only a single object file be built.) + + </para> + + </section> + + <section> + <title>Printing Detailed Build Status: the &GetBuildFailures; Function</title> + + <para> + + SCons, like most build tools, returns zero status to + the shell on success and nonzero status on failure. + Sometimes it's useful to give more information about + the build status at the end of the run, for instance + to print an informative message, send an email, or + page the poor slob who broke the build. + + </para> + + <para> + + SCons provides a &GetBuildFailures; method that + you can use in a python <function>atexit</function> function + to get a list of objects describing the actions that failed + while attempting to build targets. There can be more + than one if you're using <literal>-j</literal>. Here's a + simple example: + + </para> + + <programlisting> + import atexit + + def print_build_failures(): + from SCons.Script import GetBuildFailures + for bf in GetBuildFailures(): + print "%s failed: %s" % (bf.node, bf.errstr) + atexit.register(print_build_failures) + </programlisting> + + <para> + + The <function>atexit.register</function> call + registers <function>print_build_failures</function> + as an <function>atexit</function> callback, to be called + before &SCons; exits. When that function is called, + it calls &GetBuildFailures; to fetch the list of failed objects. + See the man page + for the detailed contents of the returned objects; + some of the more useful attributes are + <literal>.node</literal>, + <literal>.errstr</literal>, + <literal>.filename</literal>, and + <literal>.command</literal>. + The <literal>filename</literal> is not necessarily + the same file as the <literal>node</literal>; the + <literal>node</literal> is the target that was + being built when the error occurred, while the + <literal>filename</literal>is the file or dir that + actually caused the error. + Note: only call &GetBuildFailures; at the end of the + build; calling it at any other time is undefined. + + </para> + + <para> + + Here is a more complete example showing how to + turn each element of &GetBuildFailures; into a string: + + </para> + + <programlisting> + # Make the build fail if we pass fail=1 on the command line + if ARGUMENTS.get('fail', 0): + Command('target', 'source', ['/bin/false']) + + def bf_to_str(bf): + """Convert an element of GetBuildFailures() to a string + in a useful way.""" + import SCons.Errors + if bf is None: # unknown targets product None in list + return '(unknown tgt)' + elif isinstance(bf, SCons.Errors.StopError): + return str(bf) + elif bf.node: + return str(bf.node) + ': ' + bf.errstr + elif bf.filename: + return bf.filename + ': ' + bf.errstr + return 'unknown failure: ' + bf.errstr + import atexit + + def build_status(): + """Convert the build status to a 2-tuple, (status, msg).""" + from SCons.Script import GetBuildFailures + bf = GetBuildFailures() + if bf: + # bf is normally a list of build failures; if an element is None, + # it's because of a target that scons doesn't know anything about. + status = 'failed' + failures_message = "\n".join(["Failed building %s" % bf_to_str(x) + for x in bf if x is not None]) + else: + # if bf is None, the build completed successfully. + status = 'ok' + failures_message = '' + return (status, failures_message) + + def display_build_status(): + """Display the build status. Called by atexit. + Here you could do all kinds of complicated things.""" + status, failures_message = build_status() + if status == 'failed': + print "FAILED!!!!" # could display alert, ring bell, etc. + elif status == 'ok': + print "Build succeeded." + print failures_message + + atexit.register(display_build_status) + </programlisting> + + <para> + + When this runs, you'll see the appropriate output: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + scons: `.' is up to date. + Build succeeded. + % <userinput>scons -Q fail=1</userinput> + scons: *** [target] Source `source' not found, needed by target `target'. + FAILED!!!! + Failed building target: Source `source' not found, needed by target `target'. + </screen> + + </section> diff --git a/doc/user/parseconfig.in b/doc/user/parseconfig.in new file mode 100644 index 0000000..db97c35 --- /dev/null +++ b/doc/user/parseconfig.in @@ -0,0 +1,114 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + Configuring the right options to build programs to work with + libraries--especially shared libraries--that are available + on POSIX systems can be very complicated. + To help this situation, + various utilies with names that end in <filename>config</filename> + return the command-line options for the GNU Compiler Collection (GCC) + that are needed to use these libraries; + for example, the command-line options + to use a library named <filename>lib</filename> + would be found by calling a utility named <filename>lib-config</filename>. + + </para> + + <para> + + A more recent convention is that these options + are available from the generic <filename>pkg-config</filename> program, + which has common framework, error handling, and the like, + so that all the package creator has to do is provide the set of strings + for his particular package. + + </para> + + <para> + + &SCons; construction environments have a &ParseConfig; method + that executes a <filename>*config</filename> utility + (either <filename>pkg-config</filename> or a + more specific utility) + and configures the appropriate construction variables + in the environment + based on the command-line options + returned by the specified command. + + </para> + + <scons_example name="ParseConfig1"> + <file name="SConstruct" printme="1"> + env = Environment() + env['CPPPATH'] = ['/lib/compat'] + env.ParseConfig("pkg-config x11 --cflags --libs") + print env['CPPPATH'] + </file> + </scons_example> + + <para> + + &SCons; will execute the specified command string, + parse the resultant flags, + and add the flags to the appropriate environment variables. + + </para> + + <scons_output example="ParseConfig1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + In the example above, &SCons; has added the include directory to + <varname>CPPPATH</varname>. + (Depending upon what other flags are emitted by the + <filename>pkg-config</filename> command, + other variables may have been extended as well.) + + </para> + + <para> + + Note that the options are merged with existing options using + the &MergeFlags; method, + so that each option only occurs once in the construction variable: + + </para> + + <scons_example name="ParseConfig2"> + <file name="SConstruct" printme="1"> + env = Environment() + env.ParseConfig("pkg-config x11 --cflags --libs") + env.ParseConfig("pkg-config x11 --cflags --libs") + print env['CPPPATH'] + </file> + </scons_example> + + <scons_output example="ParseConfig2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> diff --git a/doc/user/parseconfig.xml b/doc/user/parseconfig.xml new file mode 100644 index 0000000..1f85ad0 --- /dev/null +++ b/doc/user/parseconfig.xml @@ -0,0 +1,132 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + Configuring the right options to build programs to work with + libraries--especially shared libraries--that are available + on POSIX systems can be very complicated. + To help this situation, + various utilies with names that end in <filename>config</filename> + return the command-line options for the GNU Compiler Collection (GCC) + that are needed to use these libraries; + for example, the command-line options + to use a library named <filename>lib</filename> + would be found by calling a utility named <filename>lib-config</filename>. + + </para> + + <para> + + A more recent convention is that these options + are available from the generic <filename>pkg-config</filename> program, + which has common framework, error handling, and the like, + so that all the package creator has to do is provide the set of strings + for his particular package. + + </para> + + <para> + + &SCons; construction environments have a &ParseConfig; method + that executes a <filename>*config</filename> utility + (either <filename>pkg-config</filename> or a + more specific utility) + and configures the appropriate construction variables + in the environment + based on the command-line options + returned by the specified command. + + </para> + + <programlisting> + env = Environment() + env['CPPPATH'] = ['/lib/compat'] + env.ParseConfig("pkg-config x11 --cflags --libs") + print env['CPPPATH'] + </programlisting> + + <para> + + &SCons; will execute the specified command string, + parse the resultant flags, + and add the flags to the appropriate environment variables. + + </para> + + <screen> + % <userinput>scons -Q</userinput> + Package x11 was not found in the pkg-config search path. + Perhaps you should add the directory containing `x11.pc' + to the PKG_CONFIG_PATH environment variable + No package 'x11' found + OSError: 'pkg-config x11 --cflags --libs' exited 1: + File "/home/my/project/SConstruct", line 3: + env.ParseConfig("pkg-config x11 --cflags --libs") + File "bootstrap/src/engine/SCons/Environment.py", line 1474: + None + File "bootstrap/src/engine/SCons/Environment.py", line 593: + None + </screen> + + <para> + + In the example above, &SCons; has added the include directory to + <varname>CPPPATH</varname>. + (Depending upon what other flags are emitted by the + <filename>pkg-config</filename> command, + other variables may have been extended as well.) + + </para> + + <para> + + Note that the options are merged with existing options using + the &MergeFlags; method, + so that each option only occurs once in the construction variable: + + </para> + + <programlisting> + env = Environment() + env.ParseConfig("pkg-config x11 --cflags --libs") + env.ParseConfig("pkg-config x11 --cflags --libs") + print env['CPPPATH'] + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + Package x11 was not found in the pkg-config search path. + Perhaps you should add the directory containing `x11.pc' + to the PKG_CONFIG_PATH environment variable + No package 'x11' found + OSError: 'pkg-config x11 --cflags --libs' exited 1: + File "/home/my/project/SConstruct", line 2: + env.ParseConfig("pkg-config x11 --cflags --libs") + File "bootstrap/src/engine/SCons/Environment.py", line 1474: + None + File "bootstrap/src/engine/SCons/Environment.py", line 593: + None + </screen> diff --git a/doc/user/parseflags.in b/doc/user/parseflags.in new file mode 100644 index 0000000..b21df4f --- /dev/null +++ b/doc/user/parseflags.in @@ -0,0 +1,184 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; has a bewildering array of construction variables + for different types of options when building programs. + Sometimes you may not know exactly which variable + should be used for a particular option. + + </para> + + <para> + + &SCons; construction environments have a &ParseFlags; method + that takes a set of typical command-line options + and distrbutes them into the appropriate construction variables. + Historically, it was created to support the &ParseConfig; method, + so it focuses on options used by the GNU Compiler Collection (GCC) + for the C and C++ toolchains. + + </para> + + <para> + + &ParseFlags; returns a dictionary containing the options + distributed into their respective construction variables. + Normally, this dictionary would be passed to &MergeFlags; + to merge the options into a &consenv;, + but the dictionary can be edited if desired to provide + additional functionality. + (Note that if the flags are not going to be edited, + calling &MergeFlags; with the options directly + will avoid an additional step.) + + </para> + + <scons_example name="ParseFlags1"> + <file name="SConstruct" printme="1"> + env = Environment() + d = env.ParseFlags("-I/opt/include -L/opt/lib -lfoo") + l = d.items() + l.sort() + for k,v in l: + if v: + print k, v + env.MergeFlags(d) + env.Program('f1.c') + </file> + <file name="f1.c"> + int main() { return 0; } + </file> + </scons_example> + + <scons_output example="ParseFlags1" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Note that if the options are limited to generic types + like those above, + they will be correctly translated for other platform types: + + </para> + + <scons_output example="ParseFlags1" os="win32"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Since the assumption is that the flags are used for the GCC toolchain, + unrecognized flags are placed in &cv-link-CCFLAGS; + so they will be used for both C and C++ compiles: + + </para> + + <scons_example name="ParseFlags2"> + <file name="SConstruct" printme="1"> + env = Environment() + d = env.ParseFlags("-whatever") + l = d.items() + l.sort() + for k,v in l: + if v: + print k, v + env.MergeFlags(d) + env.Program('f1.c') + </file> + <file name="f1.c"> + int main() { return 0; } + </file> + </scons_example> + + <scons_output example="ParseFlags2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + &ParseFlags; will also accept a (recursive) list of strings as input; + the list is flattened before the strings are processed: + + </para> + + <scons_example name="ParseFlags3"> + <file name="SConstruct" printme="1"> + env = Environment() + d = env.ParseFlags(["-I/opt/include", ["-L/opt/lib", "-lfoo"]]) + l = d.items() + l.sort() + for k,v in l: + if v: + print k, v + env.MergeFlags(d) + env.Program('f1.c') + </file> + <file name="f1.c"> + int main() { return 0; } + </file> + </scons_example> + + <scons_output example="ParseFlags3"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + If a string begins with a "!" (an exclamation mark, often called a bang), + the string is passed to the shell for execution. + The output of the command is then parsed: + + </para> + + <scons_example name="ParseFlags4"> + <file name="SConstruct" printme="1"> + env = Environment() + d = env.ParseFlags(["!echo -I/opt/include", "!echo -L/opt/lib", "-lfoo"]) + l = d.items() + l.sort() + for k,v in l: + if v: + print k, v + env.MergeFlags(d) + env.Program('f1.c') + </file> + <file name="f1.c"> + int main() { return 0; } + </file> + </scons_example> + + <scons_output example="ParseFlags4"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + &ParseFlags; is regularly updated for new options; + consult the man page for details about those currently recognized. + + </para> diff --git a/doc/user/parseflags.xml b/doc/user/parseflags.xml new file mode 100644 index 0000000..6900291 --- /dev/null +++ b/doc/user/parseflags.xml @@ -0,0 +1,199 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; has a bewildering array of construction variables + for different types of options when building programs. + Sometimes you may not know exactly which variable + should be used for a particular option. + + </para> + + <para> + + &SCons; construction environments have a &ParseFlags; method + that takes a set of typical command-line options + and distrbutes them into the appropriate construction variables. + Historically, it was created to support the &ParseConfig; method, + so it focuses on options used by the GNU Compiler Collection (GCC) + for the C and C++ toolchains. + + </para> + + <para> + + &ParseFlags; returns a dictionary containing the options + distributed into their respective construction variables. + Normally, this dictionary would be passed to &MergeFlags; + to merge the options into a &consenv;, + but the dictionary can be edited if desired to provide + additional functionality. + (Note that if the flags are not going to be edited, + calling &MergeFlags; with the options directly + will avoid an additional step.) + + </para> + + <programlisting> + env = Environment() + d = env.ParseFlags("-I/opt/include -L/opt/lib -lfoo") + l = d.items() + l.sort() + for k,v in l: + if v: + print k, v + env.MergeFlags(d) + env.Program('f1.c') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + CPPPATH ['/opt/include'] + LIBPATH ['/opt/lib'] + LIBS ['foo'] + cc -o f1.o -c -I/opt/include f1.c + cc -o f1 f1.o -L/opt/lib -lfoo + </screen> + + <para> + + Note that if the options are limited to generic types + like those above, + they will be correctly translated for other platform types: + + </para> + + <screen> + C:\><userinput>scons -Q</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + CPPPATH ['/opt/include'] + LIBPATH ['/opt/lib'] + LIBS ['foo'] + cl /Fof1.obj /c f1.c /nologo /I\opt\include + link /nologo /OUT:f1.exe /LIBPATH:\opt\lib foo.lib f1.obj + </screen> + + <para> + + Since the assumption is that the flags are used for the GCC toolchain, + unrecognized flags are placed in &cv-link-CCFLAGS; + so they will be used for both C and C++ compiles: + + </para> + + <programlisting> + env = Environment() + d = env.ParseFlags("-whatever") + l = d.items() + l.sort() + for k,v in l: + if v: + print k, v + env.MergeFlags(d) + env.Program('f1.c') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + CCFLAGS -whatever + cc -o f1.o -c -whatever f1.c + cc -o f1 f1.o + </screen> + + <para> + + &ParseFlags; will also accept a (recursive) list of strings as input; + the list is flattened before the strings are processed: + + </para> + + <programlisting> + env = Environment() + d = env.ParseFlags(["-I/opt/include", ["-L/opt/lib", "-lfoo"]]) + l = d.items() + l.sort() + for k,v in l: + if v: + print k, v + env.MergeFlags(d) + env.Program('f1.c') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + CPPPATH ['/opt/include'] + LIBPATH ['/opt/lib'] + LIBS ['foo'] + cc -o f1.o -c -I/opt/include f1.c + cc -o f1 f1.o -L/opt/lib -lfoo + </screen> + + <para> + + If a string begins with a "!" (an exclamation mark, often called a bang), + the string is passed to the shell for execution. + The output of the command is then parsed: + + </para> + + <programlisting> + env = Environment() + d = env.ParseFlags(["!echo -I/opt/include", "!echo -L/opt/lib", "-lfoo"]) + l = d.items() + l.sort() + for k,v in l: + if v: + print k, v + env.MergeFlags(d) + env.Program('f1.c') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + CPPPATH ['/opt/include'] + LIBPATH ['/opt/lib'] + LIBS ['foo'] + cc -o f1.o -c -I/opt/include f1.c + cc -o f1 f1.o -L/opt/lib -lfoo + </screen> + + <para> + + &ParseFlags; is regularly updated for new options; + consult the man page for details about those currently recognized. + + </para> diff --git a/doc/user/preface.in b/doc/user/preface.in new file mode 100644 index 0000000..de4cb43 --- /dev/null +++ b/doc/user/preface.in @@ -0,0 +1,426 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + Thank you for taking the time to read about &SCons;. + &SCons; is a next-generation + software construction tool, + or make tool--that is, a software utility + for building software (or other files) + and keeping built software up-to-date + whenever the underlying input files change. + + </para> + + <para> + + The most distinctive thing about &SCons; + is that its configuration files are + actually <emphasis>scripts</emphasis>, + written in the &Python; programming language. + This is in contrast to most alternative build tools, + which typically invent a new language to + configure the build. + &SCons; still has a learning curve, of course, + because you have to know what functions to call + to set up your build properly, + but the underlying syntax used should be familiar + to anyone who has ever looked at a Python script. + + </para> + + <para> + + Paradoxically, + using Python as the configuration file format + makes &SCons; + <emphasis>easier</emphasis> + for non-programmers to learn + than the cryptic languages of other build tools, + which are usually invented by programmers for other programmers. + This is in no small part due to the + consistency and readability that are hallmarks of Python. + It just so happens that making a real, live + scripting language the basis for the + configuration files + makes it a snap for more accomplished programmers + to do more complicated things with builds, + as necessary. + + </para> + + <!-- + + <section> + <title>Why &SCons;?</title> + + <para> + + &SCons; is a response to a perennial problem: + building software is harder than it should be. + In a nutshell: the old, reliable model of the + venerable and ubiquitous &Make; program + has had a hard time keeping up with + how complicated building software has become. + The fact that &Make; has kept up as well as it has is impressive, + and a testament to how the simplicity. + But anyone who has wrestled with &Automake; and &Autoconf; + to try to guarantee that a bit of software + will build correctly on multiple platforms + can tell you that it takes a lot of work to get right. + + </para> + + </section> + + --> + + <section> + <title>&SCons; Principles</title> + + <para> + + There are a few overriding principles + we try to live up to in designing and implementing &SCons: + + </para> + + <variablelist> + + <varlistentry> + <term>Correctness</term> + + <listitem> + <para> + + First and foremost, + by default, &SCons; guarantees a correct build + even if it means sacrificing performance a little. + We strive to guarantee the build is correct + regardless of how the software being built is structured, + how it may have been written, + or how unusual the tools are that build it. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Performance</term> + + <listitem> + <para> + + Given that the build is correct, + we try to make &SCons; build software + as quickly as possible. + In particular, wherever we may have needed to slow + down the default &SCons; behavior to guarantee a correct build, + we also try to make it easy to speed up &SCons; + through optimization options that let you trade off + guaranteed correctness in all end cases for + a speedier build in the usual cases. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Convenience</term> + + <listitem> + <para> + + &SCons; tries to do as much for you out of the box as reasonable, + including detecting the right tools on your system + and using them correctly to build the software. + + </para> + </listitem> + </varlistentry> + + </variablelist> + + <para> + + In a nutshell, we try hard to make &SCons; just + "do the right thing" and build software correctly, + with a minimum of hassles. + + </para> + + </section> + + <!-- + + <section> + <title>History</title> + + <para> + + &SCons; originated with a design + that was submitted to the Software Carpentry + design competition in 2000. + + </para> + + <para> + + &SCons; is the direct descendant + of a Perl utility called &Cons;. + &Cons; in turn based some of its ideas on &Jam;, + a build tool from Perforce Systems. + + </para> + + <para> + + XXX history of SCons + + </para> + + </section> + + --> + + <!-- + + <section> + <title>Conventions</title> + + <para> + + XXX conventions used in this manual + + </para> + + </section> + + --> + + <section> + <title>A Caveat About This Guide's Completeness</title> + + <para> + + One word of warning as you read through this Guide: + Like too much Open Source software out there, + the &SCons; documentation isn't always + kept up-to-date with the available features. + In other words, + there's a lot that &SCons; can do that + isn't yet covered in this User's Guide. + (Come to think of it, + that also describes a lot of proprietary software, doesn't it?) + + </para> + + <para> + + Although this User's Guide isn't as complete as we'd like it to be, + our development process does emphasize + making sure that the &SCons; man page is kept up-to-date + with new features. + So if you're trying to figure out how to do something + that &SCons; supports + but can't find enough (or any) information here, + it would be worth your while to look + at the man page to see if the information is covered there. + And if you do, + maybe you'd even consider contributing + a section to the User's Guide + so the next person looking for + that information won't have to + go through the same thing...? + + </para> + + </section> + + <section> + <title>Acknowledgements</title> + + <para> + + &SCons; would not exist without a lot of help + from a lot of people, + many of whom may not even be aware + that they helped or served as inspiration. + So in no particular order, + and at the risk of leaving out someone: + + </para> + + <para> + + First and foremost, + &SCons; owes a tremendous debt to Bob Sidebotham, + the original author of the classic Perl-based &Cons; tool + which Bob first released to the world back around 1996. + Bob's work on Cons classic provided the underlying architecture + and model of specifying a build configuration + using a real scripting language. + My real-world experience working on Cons + informed many of the design decisions in SCons, + including the improved parallel build support, + making Builder objects easily definable by users, + and separating the build engine from the wrapping interface. + + </para> + + <para> + + Greg Wilson was instrumental in getting + &SCons; started as a real project + when he initiated the Software Carpentry design + competition in February 2000. + Without that nudge, + marrying the advantages of the Cons classic + architecture with the readability of Python + might have just stayed no more than a nice idea. + + </para> + + <para> + + The entire &SCons; team have been + absolutely wonderful to work with, + and &SCons; would be nowhere near as useful a + tool without the energy, enthusiasm + and time people have contributed over the past few years. + The "core team" + of Chad Austin, Anthony Roach, + Bill Deegan, Charles Crain, Steve Leblanc, Greg Noel, + Gary Oberbrunner, Greg Spencer and Christoph Wiedemann + have been great about reviewing my (and other) changes + and catching problems before they get in the code base. + Of particular technical note: + Anthony's outstanding and innovative work on the tasking engine + has given &SCons; a vastly superior parallel build model; + Charles has been the master of the crucial Node infrastructure; + Christoph's work on the Configure infrastructure + has added crucial Autoconf-like functionality; + and Greg has provided excellent support + for Microsoft Visual Studio. + + </para> + + <para> + + Special thanks to David Snopek for contributing + his underlying "Autoscons" code that formed + the basis of Christoph's work with the Configure functionality. + David was extremely generous in making + this code available to &SCons;, + given that he initially released it under the GPL + and &SCons; is released under a less-restrictive MIT-style license. + + </para> + + <!-- + + <para> + + &SCons; has received contributions + from many other people, of course: + Matt Balvin (extending long command-line support on Windows), + Allen Bierbaum (extensions and fixes to Options), + Steve Christensen (help text sorting and function action signature fixes), + Michael Cook (avoiding losing signal bits from executed commands), + Derrick 'dman' Hudson (), + Alex Jacques (work on the Windows scons.bat file), + Stephen Kennedy (performance enhancements), + Lachlan O'Dea (SharedObject() support for masm + and normalized paths for the WhereIs() function), + Damyan Pepper (keeping output like Make), + Jeff Petkau (significant fixes for CacheDir and other areas), + Stefan Reichor (Ghostscript support), + Zed Shaw (Append() and Replace() environment methods), + Terrel Shumway (build and test fixes, as well as the SCons Wiki) + and + sam th (dynamic checks for utilities). + + </para> + + --> + + <para> + + Thanks to Peter Miller + for his splendid change management system, &Aegis;, + which has provided the &SCons; project + with a robust development methodology from day one, + and which showed me how you could + integrate incremental regression tests into + a practical development cycle + (years before eXtreme Programming arrived on the scene). + + </para> + + <para> + + And last, thanks to Guido van Rossum + for his elegant scripting language, + which is the basis not only for the &SCons; implementation, + but for the interface itself. + + </para> + + </section> + + <section> + <title>Contact</title> + + <para> + + The best way to contact people involved with SCons, + including the author, + is through the SCons mailing lists. + + </para> + + <para> + + If you want to ask general questions about how to use &SCons; + send email to &scons-users;. + + </para> + + <para> + + If you want to contact the &SCons; development community directly, + send email to &scons-devel;. + + </para> + + <para> + + If you want to receive announcements about &SCons, + join the low-volume &scons-announce; mailing list. + + </para> + + </section> diff --git a/doc/user/preface.xml b/doc/user/preface.xml new file mode 100644 index 0000000..2c6d8f4 --- /dev/null +++ b/doc/user/preface.xml @@ -0,0 +1,426 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + Thank you for taking the time to read about &SCons;. + &SCons; is a next-generation + software construction tool, + or make tool--that is, a software utility + for building software (or other files) + and keeping built software up-to-date + whenever the underlying input files change. + + </para> + + <para> + + The most distinctive thing about &SCons; + is that its configuration files are + actually <emphasis>scripts</emphasis>, + written in the &Python; programming language. + This is in contrast to most alternative build tools, + which typically invent a new language to + configure the build. + &SCons; still has a learning curve, of course, + because you have to know what functions to call + to set up your build properly, + but the underlying syntax used should be familiar + to anyone who has ever looked at a Python script. + + </para> + + <para> + + Paradoxically, + using Python as the configuration file format + makes &SCons; + <emphasis>easier</emphasis> + for non-programmers to learn + than the cryptic languages of other build tools, + which are usually invented by programmers for other programmers. + This is in no small part due to the + consistency and readability that are hallmarks of Python. + It just so happens that making a real, live + scripting language the basis for the + configuration files + makes it a snap for more accomplished programmers + to do more complicated things with builds, + as necessary. + + </para> + + <!-- + + <section> + <title>Why &SCons;?</title> + + <para> + + &SCons; is a response to a perennial problem: + building software is harder than it should be. + In a nutshell: the old, reliable model of the + venerable and ubiquitous &Make; program + has had a hard time keeping up with + how complicated building software has become. + The fact that &Make; has kept up as well as it has is impressive, + and a testament to how the simplicity. + But anyone who has wrestled with &Automake; and &Autoconf; + to try to guarantee that a bit of software + will build correctly on multiple platforms + can tell you that it takes a lot of work to get right. + + </para> + + </section> + + --> + + <section> + <title>&SCons; Principles</title> + + <para> + + There are a few overriding principles + we try to live up to in designing and implementing &SCons;: + + </para> + + <variablelist> + + <varlistentry> + <term>Correctness</term> + + <listitem> + <para> + + First and foremost, + by default, &SCons; guarantees a correct build + even if it means sacrificing performance a little. + We strive to guarantee the build is correct + regardless of how the software being built is structured, + how it may have been written, + or how unusual the tools are that build it. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Performance</term> + + <listitem> + <para> + + Given that the build is correct, + we try to make &SCons; build software + as quickly as possible. + In particular, wherever we may have needed to slow + down the default &SCons; behavior to guarantee a correct build, + we also try to make it easy to speed up &SCons; + through optimization options that let you trade off + guaranteed correctness in all end cases for + a speedier build in the usual cases. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Convenience</term> + + <listitem> + <para> + + &SCons; tries to do as much for you out of the box as reasonable, + including detecting the right tools on your system + and using them correctly to build the software. + + </para> + </listitem> + </varlistentry> + + </variablelist> + + <para> + + In a nutshell, we try hard to make &SCons; just + "do the right thing" and build software correctly, + with a minimum of hassles. + + </para> + + </section> + + <!-- + + <section> + <title>History</title> + + <para> + + &SCons; originated with a design + that was submitted to the Software Carpentry + design competition in 2000. + + </para> + + <para> + + &SCons; is the direct descendant + of a Perl utility called &Cons;. + &Cons; in turn based some of its ideas on &Jam;, + a build tool from Perforce Systems. + + </para> + + <para> + + XXX history of SCons + + </para> + + </section> + + --> + + <!-- + + <section> + <title>Conventions</title> + + <para> + + XXX conventions used in this manual + + </para> + + </section> + + --> + + <section> + <title>A Caveat About This Guide's Completeness</title> + + <para> + + One word of warning as you read through this Guide: + Like too much Open Source software out there, + the &SCons; documentation isn't always + kept up-to-date with the available features. + In other words, + there's a lot that &SCons; can do that + isn't yet covered in this User's Guide. + (Come to think of it, + that also describes a lot of proprietary software, doesn't it?) + + </para> + + <para> + + Although this User's Guide isn't as complete as we'd like it to be, + our development process does emphasize + making sure that the &SCons; man page is kept up-to-date + with new features. + So if you're trying to figure out how to do something + that &SCons; supports + but can't find enough (or any) information here, + it would be worth your while to look + at the man page to see if the information is covered there. + And if you do, + maybe you'd even consider contributing + a section to the User's Guide + so the next person looking for + that information won't have to + go through the same thing...? + + </para> + + </section> + + <section> + <title>Acknowledgements</title> + + <para> + + &SCons; would not exist without a lot of help + from a lot of people, + many of whom may not even be aware + that they helped or served as inspiration. + So in no particular order, + and at the risk of leaving out someone: + + </para> + + <para> + + First and foremost, + &SCons; owes a tremendous debt to Bob Sidebotham, + the original author of the classic Perl-based &Cons; tool + which Bob first released to the world back around 1996. + Bob's work on Cons classic provided the underlying architecture + and model of specifying a build configuration + using a real scripting language. + My real-world experience working on Cons + informed many of the design decisions in SCons, + including the improved parallel build support, + making Builder objects easily definable by users, + and separating the build engine from the wrapping interface. + + </para> + + <para> + + Greg Wilson was instrumental in getting + &SCons; started as a real project + when he initiated the Software Carpentry design + competition in February 2000. + Without that nudge, + marrying the advantages of the Cons classic + architecture with the readability of Python + might have just stayed no more than a nice idea. + + </para> + + <para> + + The entire &SCons; team have been + absolutely wonderful to work with, + and &SCons; would be nowhere near as useful a + tool without the energy, enthusiasm + and time people have contributed over the past few years. + The "core team" + of Chad Austin, Anthony Roach, + Bill Deegan, Charles Crain, Steve Leblanc, Greg Noel, + Gary Oberbrunner, Greg Spencer and Christoph Wiedemann + have been great about reviewing my (and other) changes + and catching problems before they get in the code base. + Of particular technical note: + Anthony's outstanding and innovative work on the tasking engine + has given &SCons; a vastly superior parallel build model; + Charles has been the master of the crucial Node infrastructure; + Christoph's work on the Configure infrastructure + has added crucial Autoconf-like functionality; + and Greg has provided excellent support + for Microsoft Visual Studio. + + </para> + + <para> + + Special thanks to David Snopek for contributing + his underlying "Autoscons" code that formed + the basis of Christoph's work with the Configure functionality. + David was extremely generous in making + this code available to &SCons;, + given that he initially released it under the GPL + and &SCons; is released under a less-restrictive MIT-style license. + + </para> + + <!-- + + <para> + + &SCons; has received contributions + from many other people, of course: + Matt Balvin (extending long command-line support on Windows), + Allen Bierbaum (extensions and fixes to Options), + Steve Christensen (help text sorting and function action signature fixes), + Michael Cook (avoiding losing signal bits from executed commands), + Derrick 'dman' Hudson (), + Alex Jacques (work on the Windows scons.bat file), + Stephen Kennedy (performance enhancements), + Lachlan O'Dea (SharedObject() support for masm + and normalized paths for the WhereIs() function), + Damyan Pepper (keeping output like Make), + Jeff Petkau (significant fixes for CacheDir and other areas), + Stefan Reichor (Ghostscript support), + Zed Shaw (Append() and Replace() environment methods), + Terrel Shumway (build and test fixes, as well as the SCons Wiki) + and + sam th (dynamic checks for utilities). + + </para> + + --> + + <para> + + Thanks to Peter Miller + for his splendid change management system, &Aegis;, + which has provided the &SCons; project + with a robust development methodology from day one, + and which showed me how you could + integrate incremental regression tests into + a practical development cycle + (years before eXtreme Programming arrived on the scene). + + </para> + + <para> + + And last, thanks to Guido van Rossum + for his elegant scripting language, + which is the basis not only for the &SCons; implementation, + but for the interface itself. + + </para> + + </section> + + <section> + <title>Contact</title> + + <para> + + The best way to contact people involved with SCons, + including the author, + is through the SCons mailing lists. + + </para> + + <para> + + If you want to ask general questions about how to use &SCons; + send email to &scons-users;. + + </para> + + <para> + + If you want to contact the &SCons; development community directly, + send email to &scons-devel;. + + </para> + + <para> + + If you want to receive announcements about &SCons;, + join the low-volume &scons-announce; mailing list. + + </para> + + </section> diff --git a/doc/user/python.in b/doc/user/python.in new file mode 100644 index 0000000..aa49030 --- /dev/null +++ b/doc/user/python.in @@ -0,0 +1,154 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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. + +--> + + <!-- + + <section> + <title>Python Overview</title> + + <para> + + This section will provide a brief overview of + the Python programming language. + Skip this section if you are already familiar with Python + (or you're really intent on diving into &SCons; + and just picking up things as you go). + + </para> + + <para> + + Python has a lot of good + documentation freely available on-line + to help you get started. + The standard tutorial is available at XXX. + + + </para> + + <para> + + Python is very easy to pick up. + + </para> + + <para> + + Python variables must be assigned to before they can be referenced. + + </para> + + <para> + + Assignment is like most programming languages: + + x = 1 + 2 + z = 3 * x + + </para> + + <para> + + Function calls look like most language function calls: + + a = f(g) + + </para> + + <para> + + Define functions like so: + + def func(arg1, arg2): + return arg1 * arg 2 + + The number of parameters + + </para> + + <para> + + Strings can be enclosed in single quotes or double quotes, + backslashes are used to escape characters, + triple-quote syntax lets you include quotes and newlines, + raw strings begin with 'r'. + + </para> + + <para> + + Lists are enclosed in square brackets, + list items are separated by commas. + List references use square brackets and integer index values, + slice notation lets you select, delete or replace a range. + + </para> + + <para> + + Dictionaries (hashes) are enclosed in curly brackets, + : separates keys from values, + , separates items. + Dictionary values are referenced using square brackets. + + </para> + + <para> + + Access class attributes (including methods) using a '.'. + + </para> + + <para> + + if: statements look like + + elif: statements look like + + else: statements look like + + </para> + + <para> + + for: statements look like + + while: statements look like + + break statements look like + + continue statements look like + + </para> + + <para> + + pass + + </para> + + </section> + + --> diff --git a/doc/user/python.xml b/doc/user/python.xml new file mode 100644 index 0000000..aa49030 --- /dev/null +++ b/doc/user/python.xml @@ -0,0 +1,154 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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. + +--> + + <!-- + + <section> + <title>Python Overview</title> + + <para> + + This section will provide a brief overview of + the Python programming language. + Skip this section if you are already familiar with Python + (or you're really intent on diving into &SCons; + and just picking up things as you go). + + </para> + + <para> + + Python has a lot of good + documentation freely available on-line + to help you get started. + The standard tutorial is available at XXX. + + + </para> + + <para> + + Python is very easy to pick up. + + </para> + + <para> + + Python variables must be assigned to before they can be referenced. + + </para> + + <para> + + Assignment is like most programming languages: + + x = 1 + 2 + z = 3 * x + + </para> + + <para> + + Function calls look like most language function calls: + + a = f(g) + + </para> + + <para> + + Define functions like so: + + def func(arg1, arg2): + return arg1 * arg 2 + + The number of parameters + + </para> + + <para> + + Strings can be enclosed in single quotes or double quotes, + backslashes are used to escape characters, + triple-quote syntax lets you include quotes and newlines, + raw strings begin with 'r'. + + </para> + + <para> + + Lists are enclosed in square brackets, + list items are separated by commas. + List references use square brackets and integer index values, + slice notation lets you select, delete or replace a range. + + </para> + + <para> + + Dictionaries (hashes) are enclosed in curly brackets, + : separates keys from values, + , separates items. + Dictionary values are referenced using square brackets. + + </para> + + <para> + + Access class attributes (including methods) using a '.'. + + </para> + + <para> + + if: statements look like + + elif: statements look like + + else: statements look like + + </para> + + <para> + + for: statements look like + + while: statements look like + + break statements look like + + continue statements look like + + </para> + + <para> + + pass + + </para> + + </section> + + --> diff --git a/doc/user/repositories.in b/doc/user/repositories.in new file mode 100644 index 0000000..8c97b02 --- /dev/null +++ b/doc/user/repositories.in @@ -0,0 +1,641 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + 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> + + It's often useful to allow multiple programmers working + on a project to build software from + source files and/or derived files that + are stored in a centrally-accessible repository, + a directory copy of the source code tree. + (Note that this is not the sort of repository + maintained by a source code management system + like BitKeeper, CVS, or Subversion.) + <!-- + For information about using &SCons; + with these systems, see the section, + "Fetching Files From Source Code Management Systems," + below.) + --> + 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> + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Program('hello.c') + Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + 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. + 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/repository2/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> + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <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> + + <scons_example name="ex2"> + <file name="SConstruct"> + env = Environment() + env.Program('hello.c') + Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2') + </file> + <file name="__ROOT__/usr/repository1/hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <scons_output example="ex2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <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> + + <scons_example name="ex3"> + <file name="SConstruct"> + env = Environment() + env.Program('hello.c') + Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2') + </file> + <file name="__ROOT__/usr/repository2/hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <scons_output example="ex3"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + </para> + + </section> + + <section> + <title>Finding <literal>#include</literal> files in repositories</title> + + <para> + + We've already seen that SCons will scan the contents of + a source file for <literal>#include</literal> file names + and realize that targets built from that source file + also depend on the <literal>#include</literal> file(s). + For each directory in the &cv-link-CPPPATH; list, + &SCons; will actually search the corresponding directories + in any repository trees and establish the + correct dependencies on any + <literal>#include</literal> files that it finds + in repository directory. + + </para> + + <para> + + Unless the C compiler also knows about these directories + in the repository trees, though, + it will be unable to find the <literal>#include</literal> files. + If, for example, the &hello_c; file in + our previous example includes the &hello.h; + in its current directory, + and the &hello.h; only exists in the repository: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + hello.c:1: hello.h: No such file or directory + </screen> + + <para> + + In order to inform the C compiler about the repositories, + &SCons; will add appropriate + <literal>-I</literal> flags to the compilation commands + for each directory in the &cv-CPPPATH; list. + So if we add the current directory to the + construction environment &cv-CPPPATH; like so: + + </para> + + <scons_example name="CPPPATH"> + <file name="SConstruct" printme="1"> + env = Environment(CPPPATH = ['.']) + env.Program('hello.c') + Repository('__ROOT__/usr/repository1') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + Then re-executing &SCons; yields: + + </para> + + <scons_output example="CPPPATH"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + The order of the <literal>-I</literal> options replicates, + for the C preprocessor, + the same repository-directory search path + that &SCons; uses for its own dependency analysis. + If there are multiple repositories and multiple &cv-CPPPATH; + directories, &SCons; will add the repository directories + to the beginning of each &cv-CPPPATH; directory, + rapidly multiplying the number of <literal>-I</literal> flags. + If, for example, the &cv-CPPPATH; contains three directories + (and shorter repository path names!): + + </para> + + <scons_example name="CPPPATH3"> + <file name="SConstruct" printme="1"> + env = Environment(CPPPATH = ['dir1', 'dir2', 'dir3']) + env.Program('hello.c') + Repository('__ROOT__/r1', '__ROOT__/r2') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + Then we'll end up with nine <literal>-I</literal> options + on the command line, + three (for each of the &cv-CPPPATH; directories) + times three (for the local directory plus the two repositories): + + </para> + + <scons_output example="CPPPATH3"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + +<!-- + +Cons classic did the following, does SCons? + +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.) + +--> + + <section> + <title>Limitations on <literal>#include</literal> files in repositories</title> + + <para> + + &SCons; relies on the C compiler's + <literal>-I</literal> options to control the order in which + the preprocessor will search the repository directories + for <literal>#include</literal> files. + This causes a problem, however, with how the C preprocessor + handles <literal>#include</literal> lines with + the file name included in double-quotes. + + </para> + + <para> + + As we've seen, + &SCons; will compile the &hello_c; file from + the repository if it doesn't exist in + the local directory. + If, however, the &hello_c; file in the repository contains + a <literal>#include</literal> line with the file name in + double quotes: + + </para> + + <programlisting> + #include "hello.h" + int + main(int argc, char *argv[]) + { + printf(HELLO_MESSAGE); + return (0); + } + </programlisting> + + <para> + + Then the C preprocessor will <emphasis>always</emphasis> + use a &hello_h; file from the repository directory first, + even if there is a &hello_h; file in the local directory, + despite the fact that the command line specifies + <literal>-I</literal> as the first option: + + </para> + + <scons_example name="quote1"> + <file name="SConstruct"> + env = Environment(CPPPATH = ['.']) + env.Program('hello.c') + Repository('__ROOT__/usr/repository1') + </file> + <file name="__ROOT__/usr/repository1/hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <scons_output example="quote1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + This behavior of the C preprocessor--always search + for a <literal>#include</literal> file in double-quotes + first in the same directory as the source file, + and only then search the <literal>-I</literal>--can + not, in general, be changed. + In other words, it's a limitation + that must be lived with if you want to use + code repositories in this way. + There are three ways you can possibly + work around this C preprocessor behavior: + + </para> + + <orderedlist> + + <listitem> + <para> + + Some modern versions of C compilers do have an option + to disable or control this behavior. + If so, add that option to &cv-link-CFLAGS; + (or &cv-link-CXXFLAGS; or both) in your construction environment(s). + Make sure the option is used for all construction + environments that use C preprocessing! + + </para> + </listitem> + + <listitem> + <para> + + Change all occurrences of <literal>#include "file.h"</literal> + to <literal>#include &lt;file.h&gt;</literal>. + Use of <literal>#include</literal> with angle brackets + does not have the same behavior--the <literal>-I</literal> + directories are searched first + for <literal>#include</literal> files--which + gives &SCons; direct control over the list of + directories the C preprocessor will search. + + </para> + </listitem> + + <listitem> + <para> + + Require that everyone working with compilation from + repositories check out and work on entire directories of files, + not individual files. + (If you use local wrapper scripts around + your source code control system's command, + you could add logic to enforce this restriction there. + + </para> + </listitem> + + </orderedlist> + + </section> + + </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> option: + + </para> + + <screen> + % <userinput>scons -Q -Y /usr/repository1 -Y /usr/repository2</userinput> + </screen> + + <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 executables), &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 run &SCons; in a separate build directory + and copy the resulting tree to the desired repository: + + </para> + + <scons_example name="ex4"> + <file name="SConstruct"> + env = Environment() + env.Program(['hello.c', 'file1.c', 'file2.c']) + Repository('/usr/repository1', '/usr/repository2') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + <file name="file1.c"> + int f1() { printf("file1\n"); } + </file> + <file name="file2.c"> + int f2() { printf("file2.c\n"); } + </file> + </scons_example> + + <scons_output example="ex4"> + <scons_output_command>cd /usr/repository1</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <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> + + <!-- + <scons_output example="ex4"> + <scons_output_command>cd $HOME/build</scons_output_command> + <scons_output_command>edit hello.c</scons_output_command> + <scons_output_command>scons -Q -Y __ROOT__/usr/repository1</scons_output_command> + </scons_output> + --> + <screen> + % <userinput>cd $HOME/build</userinput> + % <userinput>edit hello.c</userinput> + % <userinput>scons -Q -Y /usr/repository1</userinput> + cc -c -o hello.o hello.c + cc -o hello hello.o /usr/repository1/file1.o /usr/repository1/file2.o + </screen> + + <para> + + Notice that &SCons; realizes that it does not need to + rebuild local copies <filename>file1.o</filename> and <filename>file2.o</filename> files, + but instead uses the already-compiled files + from the repository. + + </para> + + </section> + + <section> + <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> + + <screen> + % <userinput>mkdir $HOME/build2</userinput> + % <userinput>cd $HOME/build2</userinput> + % <userinput>scons -Q -Y /usr/all/repository hello</userinput> + scons: `hello' is up-to-date. + </screen> + + <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> + + <scons_example name="ex5"> + <file name="SConstruct" printme="1"> + env = Environment() + hello = env.Program('hello.c') + Local(hello) + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <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> + + <screen> + % <userinput>scons -Y /usr/all/repository hello</userinput> + Local copy of hello from /usr/all/repository/hello + scons: `hello' is up-to-date. + </screen> + + <para> + + (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.) + + </para> + + </section> diff --git a/doc/user/repositories.xml b/doc/user/repositories.xml new file mode 100644 index 0000000..7d955c3 --- /dev/null +++ b/doc/user/repositories.xml @@ -0,0 +1,595 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + 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> + + It's often useful to allow multiple programmers working + on a project to build software from + source files and/or derived files that + are stored in a centrally-accessible repository, + a directory copy of the source code tree. + (Note that this is not the sort of repository + maintained by a source code management system + like BitKeeper, CVS, or Subversion.) + <!-- + For information about using &SCons; + with these systems, see the section, + "Fetching Files From Source Code Management Systems," + below.) + --> + 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> + + 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. + 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/repository2/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> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + <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> + + + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c /usr/repository1/hello.c + cc -o hello hello.o + </screen> + + <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> + + + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c /usr/repository2/hello.c + cc -o hello hello.o + </screen> + + <para> + + </para> + + </section> + + <section> + <title>Finding <literal>#include</literal> files in repositories</title> + + <para> + + We've already seen that SCons will scan the contents of + a source file for <literal>#include</literal> file names + and realize that targets built from that source file + also depend on the <literal>#include</literal> file(s). + For each directory in the &cv-link-CPPPATH; list, + &SCons; will actually search the corresponding directories + in any repository trees and establish the + correct dependencies on any + <literal>#include</literal> files that it finds + in repository directory. + + </para> + + <para> + + Unless the C compiler also knows about these directories + in the repository trees, though, + it will be unable to find the <literal>#include</literal> files. + If, for example, the &hello_c; file in + our previous example includes the &hello;.h; + in its current directory, + and the &hello;.h; only exists in the repository: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c hello.c + hello.c:1: hello.h: No such file or directory + </screen> + + <para> + + In order to inform the C compiler about the repositories, + &SCons; will add appropriate + <literal>-I</literal> flags to the compilation commands + for each directory in the &cv-CPPPATH; list. + So if we add the current directory to the + construction environment &cv-CPPPATH; like so: + + </para> + + <programlisting> + env = Environment(CPPPATH = ['.']) + env.Program('hello.c') + Repository('/usr/repository1') + </programlisting> + + <para> + + Then re-executing &SCons; yields: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c -I. -I/usr/repository1 hello.c + cc -o hello hello.o + </screen> + + <para> + + The order of the <literal>-I</literal> options replicates, + for the C preprocessor, + the same repository-directory search path + that &SCons; uses for its own dependency analysis. + If there are multiple repositories and multiple &cv-CPPPATH; + directories, &SCons; will add the repository directories + to the beginning of each &cv-CPPPATH; directory, + rapidly multiplying the number of <literal>-I</literal> flags. + If, for example, the &cv-CPPPATH; contains three directories + (and shorter repository path names!): + + </para> + + <programlisting> + env = Environment(CPPPATH = ['dir1', 'dir2', 'dir3']) + env.Program('hello.c') + Repository('/r1', '/r2') + </programlisting> + + <para> + + Then we'll end up with nine <literal>-I</literal> options + on the command line, + three (for each of the &cv-CPPPATH; directories) + times three (for the local directory plus the two repositories): + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c -Idir1 -I/r1/dir1 -I/r2/dir1 -Idir2 -I/r1/dir2 -I/r2/dir2 -Idir3 -I/r1/dir3 -I/r2/dir3 hello.c + cc -o hello hello.o + </screen> + +<!-- + +Cons classic did the following, does SCons? + +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.) + +--> + + <section> + <title>Limitations on <literal>#include</literal> files in repositories</title> + + <para> + + &SCons; relies on the C compiler's + <literal>-I</literal> options to control the order in which + the preprocessor will search the repository directories + for <literal>#include</literal> files. + This causes a problem, however, with how the C preprocessor + handles <literal>#include</literal> lines with + the file name included in double-quotes. + + </para> + + <para> + + As we've seen, + &SCons; will compile the &hello_c; file from + the repository if it doesn't exist in + the local directory. + If, however, the &hello_c; file in the repository contains + a <literal>#include</literal> line with the file name in + double quotes: + + </para> + + <programlisting> + #include "hello.h" + int + main(int argc, char *argv[]) + { + printf(HELLO_MESSAGE); + return (0); + } + </programlisting> + + <para> + + Then the C preprocessor will <emphasis>always</emphasis> + use a &hello_h; file from the repository directory first, + even if there is a &hello_h; file in the local directory, + despite the fact that the command line specifies + <literal>-I</literal> as the first option: + + </para> + + + + <screen> + % <userinput>scons -Q</userinput> + cc -o hello.o -c -I. -I/usr/repository1 /usr/repository1/hello.c + cc -o hello hello.o + </screen> + + <para> + + This behavior of the C preprocessor--always search + for a <literal>#include</literal> file in double-quotes + first in the same directory as the source file, + and only then search the <literal>-I</literal>--can + not, in general, be changed. + In other words, it's a limitation + that must be lived with if you want to use + code repositories in this way. + There are three ways you can possibly + work around this C preprocessor behavior: + + </para> + + <orderedlist> + + <listitem> + <para> + + Some modern versions of C compilers do have an option + to disable or control this behavior. + If so, add that option to &cv-link-CFLAGS; + (or &cv-link-CXXFLAGS; or both) in your construction environment(s). + Make sure the option is used for all construction + environments that use C preprocessing! + + </para> + </listitem> + + <listitem> + <para> + + Change all occurrences of <literal>#include "file.h"</literal> + to <literal>#include <file.h></literal>. + Use of <literal>#include</literal> with angle brackets + does not have the same behavior--the <literal>-I</literal> + directories are searched first + for <literal>#include</literal> files--which + gives &SCons; direct control over the list of + directories the C preprocessor will search. + + </para> + </listitem> + + <listitem> + <para> + + Require that everyone working with compilation from + repositories check out and work on entire directories of files, + not individual files. + (If you use local wrapper scripts around + your source code control system's command, + you could add logic to enforce this restriction there. + + </para> + </listitem> + + </orderedlist> + + </section> + + </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> option: + + </para> + + <screen> + % <userinput>scons -Q -Y /usr/repository1 -Y /usr/repository2</userinput> + </screen> + + <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 executables), &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 run &SCons; in a separate build directory + and copy the resulting tree to the desired repository: + + </para> + + + + <screen> + % <userinput>cd /usr/repository1</userinput> + % <userinput>scons -Q</userinput> + cc -o file1.o -c file1.c + cc -o file2.o -c file2.c + cc -o hello.o -c hello.c + cc -o hello hello.o file1.o file2.o + </screen> + + <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> + + <!-- + <scons_output example="ex4"> + <scons_output_command>cd $HOME/build</scons_output_command> + <scons_output_command>edit hello.c</scons_output_command> + <scons_output_command>scons -Q -Y __ROOT__/usr/repository1</scons_output_command> + </scons_output> + --> + <screen> + % <userinput>cd $HOME/build</userinput> + % <userinput>edit hello.c</userinput> + % <userinput>scons -Q -Y /usr/repository1</userinput> + cc -c -o hello.o hello.c + cc -o hello hello.o /usr/repository1/file1.o /usr/repository1/file2.o + </screen> + + <para> + + Notice that &SCons; realizes that it does not need to + rebuild local copies <filename>file1.o</filename> and <filename>file2.o</filename> files, + but instead uses the already-compiled files + from the repository. + + </para> + + </section> + + <section> + <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> + + <screen> + % <userinput>mkdir $HOME/build2</userinput> + % <userinput>cd $HOME/build2</userinput> + % <userinput>scons -Q -Y /usr/all/repository hello</userinput> + scons: `hello' is up-to-date. + </screen> + + <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> + + <screen> + % <userinput>scons -Y /usr/all/repository hello</userinput> + Local copy of hello from /usr/all/repository/hello + scons: `hello' is up-to-date. + </screen> + + <para> + + (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.) + + </para> + + </section> diff --git a/doc/user/run.in b/doc/user/run.in new file mode 100644 index 0000000..946a7ed --- /dev/null +++ b/doc/user/run.in @@ -0,0 +1,375 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 Invoking Cons + +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). + +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: + + % cd libfoo/subdir + % cons -t target + +is exactly equivalent to: + + % 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. + + +=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> + + XXX + + </para> + + <section> + <title>Command-Line Options</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Getting at Command-Line Arguments</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Selective Builds</title> + + <para> + + XXX + + </para> + + </section> + + <!-- + + <section> + <title>Build Pruning</title> + + <para> + + XXX + + </para> + + </section> + + --> + + <section> + <title>Overriding Construction Variables</title> + + <para> + + XXX + + </para> + + </section> diff --git a/doc/user/run.xml b/doc/user/run.xml new file mode 100644 index 0000000..946a7ed --- /dev/null +++ b/doc/user/run.xml @@ -0,0 +1,375 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 Invoking Cons + +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). + +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: + + % cd libfoo/subdir + % cons -t target + +is exactly equivalent to: + + % 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. + + +=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> + + XXX + + </para> + + <section> + <title>Command-Line Options</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Getting at Command-Line Arguments</title> + + <para> + + XXX + + </para> + + </section> + + <section> + <title>Selective Builds</title> + + <para> + + XXX + + </para> + + </section> + + <!-- + + <section> + <title>Build Pruning</title> + + <para> + + XXX + + </para> + + </section> + + --> + + <section> + <title>Overriding Construction Variables</title> + + <para> + + XXX + + </para> + + </section> diff --git a/doc/user/scanners.in b/doc/user/scanners.in new file mode 100644 index 0000000..8fa36d7 --- /dev/null +++ b/doc/user/scanners.in @@ -0,0 +1,331 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 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> + + &SCons; has built-in scanners that know how to look in + C, Fortran and IDL source files for information about + other files that targets built from those files depend on--for example, + in the case of files that use the C preprocessor, + the <filename>.h</filename> files that are specified + using <literal>#include</literal> lines in the source. + You can use the same mechanisms that &SCons; uses to create + its built-in scanners to write scanners of your own for file types + that &SCons; does not know how to scan "out of the box." + + </para> + + <section> + <title>A Simple Scanner Example</title> + + <para> + + Suppose, for example, that we want to create a simple scanner + for <filename>.foo</filename> files. + A <filename>.foo</filename> file contains some text that + will be processed, + and can include other files on lines that begin + with <literal>include</literal> + followed by a file name: + + </para> + + <programlisting> + include filename.foo + </programlisting> + + <para> + + Scanning a file will be handled by a Python function + that you must supply. + Here is a function that will use the Python + <filename>re</filename> module + to scan for the <literal>include</literal> lines in our example: + + </para> + + <programlisting> + import re + + include_re = re.compile(r'^include\s+(\S+)$', re.M) + + def kfile_scan(node, env, path, arg): + contents = node.get_text_contents() + return include_re.findall(contents) + </programlisting> + + <para> + + The scanner function must + accept the four specified arguments + and return a list of implicit dependencies. + Presumably, these would be dependencies found + from examining the contents of the file, + although the function can perform any + manipulation at all to generate the list of + dependencies. + + </para> + + <variablelist> + + <varlistentry> + <term>node</term> + + <listitem> + <para> + + An &SCons; node object representing the file being scanned. + The path name to the file can be + used by converting the node to a string + using the <literal>str()</literal> function, + or an internal &SCons; <literal>get_text_contents()</literal> + object method can be used to fetch the contents. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>env</term> + + <listitem> + <para> + + The construction environment in effect for this scan. + The scanner function may choose to use construction + variables from this environment to affect its behavior. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>path</term> + + <listitem> + <para> + + A list of directories that form the search path for included files + for this scanner. + This is how &SCons; handles the &cv-link-CPPPATH; and &cv-link-LIBPATH; + variables. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>arg</term> + + <listitem> + <para> + + An optional argument that you can choose to + have passed to this scanner function by + various scanner instances. + + </para> + </listitem> + </varlistentry> + + </variablelist> + + <para> + + A Scanner object is created using the &Scanner; function, + which typically takes an <literal>skeys</literal> argument + to associate the type of file suffix with this scanner. + The Scanner object must then be associated with the + &cv-link-SCANNERS; construction variable of a construction environment, + typically by using the &Append; method: + + </para> + + <programlisting> + kscan = Scanner(function = kfile_scan, + skeys = ['.k']) + env.Append(SCANNERS = kscan) + </programlisting> + + <para> + + When we put it all together, it looks like: + + </para> + + <scons_example name="scan"> + <file name="SConstruct" printme="1"> + import re + + include_re = re.compile(r'^include\s+(\S+)$', re.M) + + def kfile_scan(node, env, path): + contents = node.get_text_contents() + includes = include_re.findall(contents) + return includes + + kscan = Scanner(function = kfile_scan, + skeys = ['.k']) + + env = Environment(ENV = {'PATH' : '__ROOT__/usr/local/bin'}) + env.Append(SCANNERS = kscan) + + env.Command('foo', 'foo.k', 'kprocess < $SOURCES > $TARGET') + </file> + <file name="foo.k"> + include other_file + </file> + <file name="other_file"> + other_file + </file> + <directory name="__ROOT__/usr"></directory> + <directory name="__ROOT__/usr/local"></directory> + <directory name="__ROOT__/usr/local/bin"></directory> + <file name="__ROOT_/usr/local/bin/kprocess" chmod="755"> + cat + </file> + </scons_example> + + <!-- + + <para> + + Now if we run &scons; + and then re-run it after changing the contents of + <filename>other_file</filename>, + the <filename>foo</filename> + target file will be automatically rebuilt: + + </para> + + <scons_output example="scan"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command output=" [CHANGE THE CONTENTS OF other_file]">edit other_file</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + </section> diff --git a/doc/user/scanners.xml b/doc/user/scanners.xml new file mode 100644 index 0000000..d34b222 --- /dev/null +++ b/doc/user/scanners.xml @@ -0,0 +1,317 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 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> + + &SCons; has built-in scanners that know how to look in + C, Fortran and IDL source files for information about + other files that targets built from those files depend on--for example, + in the case of files that use the C preprocessor, + the <filename>.h</filename> files that are specified + using <literal>#include</literal> lines in the source. + You can use the same mechanisms that &SCons; uses to create + its built-in scanners to write scanners of your own for file types + that &SCons; does not know how to scan "out of the box." + + </para> + + <section> + <title>A Simple Scanner Example</title> + + <para> + + Suppose, for example, that we want to create a simple scanner + for <filename>.foo</filename> files. + A <filename>.foo</filename> file contains some text that + will be processed, + and can include other files on lines that begin + with <literal>include</literal> + followed by a file name: + + </para> + + <programlisting> + include filename.foo + </programlisting> + + <para> + + Scanning a file will be handled by a Python function + that you must supply. + Here is a function that will use the Python + <filename>re</filename> module + to scan for the <literal>include</literal> lines in our example: + + </para> + + <programlisting> + import re + + include_re = re.compile(r'^include\s+(\S+)$', re.M) + + def kfile_scan(node, env, path, arg): + contents = node.get_text_contents() + return include_re.findall(contents) + </programlisting> + + <para> + + The scanner function must + accept the four specified arguments + and return a list of implicit dependencies. + Presumably, these would be dependencies found + from examining the contents of the file, + although the function can perform any + manipulation at all to generate the list of + dependencies. + + </para> + + <variablelist> + + <varlistentry> + <term>node</term> + + <listitem> + <para> + + An &SCons; node object representing the file being scanned. + The path name to the file can be + used by converting the node to a string + using the <literal>str()</literal> function, + or an internal &SCons; <literal>get_text_contents()</literal> + object method can be used to fetch the contents. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>env</term> + + <listitem> + <para> + + The construction environment in effect for this scan. + The scanner function may choose to use construction + variables from this environment to affect its behavior. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>path</term> + + <listitem> + <para> + + A list of directories that form the search path for included files + for this scanner. + This is how &SCons; handles the &cv-link-CPPPATH; and &cv-link-LIBPATH; + variables. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>arg</term> + + <listitem> + <para> + + An optional argument that you can choose to + have passed to this scanner function by + various scanner instances. + + </para> + </listitem> + </varlistentry> + + </variablelist> + + <para> + + A Scanner object is created using the &Scanner; function, + which typically takes an <literal>skeys</literal> argument + to associate the type of file suffix with this scanner. + The Scanner object must then be associated with the + &cv-link-SCANNERS; construction variable of a construction environment, + typically by using the &Append; method: + + </para> + + <programlisting> + kscan = Scanner(function = kfile_scan, + skeys = ['.k']) + env.Append(SCANNERS = kscan) + </programlisting> + + <para> + + When we put it all together, it looks like: + + </para> + + <programlisting> + import re + + include_re = re.compile(r'^include\s+(\S+)$', re.M) + + def kfile_scan(node, env, path): + contents = node.get_text_contents() + includes = include_re.findall(contents) + return includes + + kscan = Scanner(function = kfile_scan, + skeys = ['.k']) + + env = Environment(ENV = {'PATH' : '/usr/local/bin'}) + env.Append(SCANNERS = kscan) + + env.Command('foo', 'foo.k', 'kprocess < $SOURCES > $TARGET') + </programlisting> + + <!-- + + <para> + + Now if we run &scons; + and then re-run it after changing the contents of + <filename>other_file</filename>, + the <filename>foo</filename> + target file will be automatically rebuilt: + + </para> + + <scons_output example="scan"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command output=" [CHANGE THE CONTENTS OF other_file]">edit other_file</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + </section> diff --git a/doc/user/sconf.in b/doc/user/sconf.in new file mode 100644 index 0000000..c4092c9 --- /dev/null +++ b/doc/user/sconf.in @@ -0,0 +1,486 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; has integrated support for multi-platform build configuration + similar to that offered by GNU &Autoconf;, + such as + figuring out what libraries or header files + are available on the local system. + This section describes how to use + this &SCons feature. + + </para> + + <note> + <para> + This chapter is still under development, + so not everything is explained as well as it should be. + See the &SCons; man page for additional information. + </para> + </note> + + <section> + <title>&Configure_Contexts;</title> + + <para> + + The basic framework for multi-platform build configuration + in &SCons; is to attach a &configure_context; to a + construction environment by calling the &Configure; function, + perform a number of checks for + libraries, functions, header files, etc., + and to then call the configure context's &Finish; method + to finish off the configuration: + + </para> + + <sconstruct> + env = Environment() + conf = Configure(env) + # Checks for libraries, header files, etc. go here! + env = conf.Finish() + </sconstruct> + + <para> + + &SCons; provides a number of basic checks, + as well as a mechanism for adding your own custom checks. + + </para> + + <para> + + Note that &SCons; uses its own dependency + mechanism to determine when a check + needs to be run--that is, + &SCons; does not run the checks + every time it is invoked, + but caches the values returned by previous checks + and uses the cached values unless something has changed. + This saves a tremendous amount + of developer time while working on + cross-platform build issues. + + </para> + + <para> + + The next sections describe + the basic checks that &SCons; supports, + as well as how to add your own custom checks. + + </para> + + </section> + + <section> + <title>Checking for the Existence of Header Files</title> + + <para> + + Testing the existence of a header file + requires knowing what language the header file is. + A configure context has a &CheckCHeader; method + that checks for the existence of a C header file: + + </para> + + <sconstruct> + env = Environment() + conf = Configure(env) + if not conf.CheckCHeader('math.h'): + print 'Math.h must be installed!' + Exit(1) + if conf.CheckCHeader('foo.h'): + conf.env.Append('-DHAS_FOO_H') + env = conf.Finish() + </sconstruct> + + <para> + + Note that you can choose to terminate + the build if a given header file doesn't exist, + or you can modify the construction environment + based on the existence of a header file. + + </para> + + <para> + + If you need to check for the existence + a C++ header file, + use the &CheckCXXHeader; method: + + </para> + + <sconstruct> + env = Environment() + conf = Configure(env) + if not conf.CheckCXXHeader('vector.h'): + print 'vector.h must be installed!' + Exit(1) + env = conf.Finish() + </sconstruct> + + </section> + + <section> + <title>Checking for the Availability of a Function</title> + + <para> + + Check for the availability of a specific function + using the &CheckFunc; method: + + </para> + + <sconstruct> + env = Environment() + conf = Configure(env) + if not conf.CheckFunc('strcpy'): + print 'Did not find strcpy(), using local version' + conf.env.Append(CPPDEFINES = '-Dstrcpy=my_local_strcpy') + env = conf.Finish() + </sconstruct> + + </section> + + <section> + <title>Checking for the Availability of a Library</title> + + <para> + + Check for the availability of a library + using the &CheckLib; method. + You only specify the basename of the library, + you don't need to add a <literal>lib</literal> + prefix or a <literal>.a</literal> or <literal>.lib</literal> suffix: + + </para> + + <sconstruct> + env = Environment() + conf = Configure(env) + if not conf.CheckLib('m'): + print 'Did not find libm.a or m.lib, exiting!' + Exit(1) + env = conf.Finish() + </sconstruct> + + <para> + + Because the ability to use a library successfully + often depends on having access to a header file + that describes the library's interface, + you can check for a library + <emphasis>and</emphasis> a header file + at the same time by using the + &CheckLibWithHeader; method: + + </para> + + <sconstruct> + env = Environment() + conf = Configure(env) + if not conf.CheckLibWithHeader('m', 'math.h', 'c'): + print 'Did not find libm.a or m.lib, exiting!' + Exit(1) + env = conf.Finish() + </sconstruct> + + <para> + + This is essentially shorthand for + separate calls to the &CheckHeader; and &CheckLib; + functions. + + </para> + + </section> + + <section> + <title>Checking for the Availability of a &typedef;</title> + + <para> + + Check for the availability of a &typedef; + by using the &CheckType; method: + + </para> + + <sconstruct> + env = Environment() + conf = Configure(env) + if not conf.CheckType('off_t'): + print 'Did not find off_t typedef, assuming int' + conf.env.Append(CCFLAGS = '-Doff_t=int') + env = conf.Finish() + </sconstruct> + + <para> + + You can also add a string that will be + placed at the beginning of the test file + that will be used to check for the &typedef;. + This provide a way to specify + files that must be included to find the &typedef;: + + </para> + + <sconstruct> + env = Environment() + conf = Configure(env) + if not conf.CheckType('off_t', '#include &lt;sys/types.h&gt;\n'): + print 'Did not find off_t typedef, assuming int' + conf.env.Append(CCFLAGS = '-Doff_t=int') + env = conf.Finish() + </sconstruct> + + </section> + + <section> + <title>Adding Your Own Custom Checks</title> + + <para> + + A custom check is a Python function + that checks for a certain condition to exist + on the running system, + usually using methods that &SCons; + supplies to take care of the details + of checking whether a compilation succeeds, + a link succeeds, + a program is runnable, + etc. + A simple custom check for the existence of + a specific library might look as follows: + + </para> + + <sconstruct> + mylib_test_source_file = """ + #include &lt;mylib.h&gt; + int main(int argc, char **argv) + { + MyLibrary mylib(argc, argv); + return 0; + } + """ + + def CheckMyLibrary(context): + context.Message('Checking for MyLibrary...') + result = context.TryLink(mylib_test_source_file, '.c') + context.Result(result) + return result + </sconstruct> + + <para> + + The &Message; and &Result; methods + should typically begin and end a custom check to + let the user know what's going on: + the &Message; call prints the + specified message (with no trailing newline) + and the &Result; call prints + <literal>yes</literal> if the check succeeds and + <literal>no</literal> if it doesn't. + The &TryLink; method + actually tests for whether the + specified program text + will successfully link. + + </para> + + <para> + + (Note that a custom check can modify + its check based on any arguments you + choose to pass it, + or by using or modifying the configure context environment + in the <literal>context.env</literal> attribute.) + + </para> + + <para> + + This custom check function is + then attached to the &configure_context; + by passing a dictionary + to the &Configure; call + that maps a name of the check + to the underlying function: + + </para> + + <sconstruct> + env = Environment() + conf = Configure(env, custom_tests = {'CheckMyLibrary' : CheckMyLibrary}) + </sconstruct> + + <para> + + You'll typically want to make + the check and the function name the same, + as we've done here, + to avoid potential confusion. + + </para> + + <para> + + We can then put these pieces together + and actually call the <literal>CheckMyLibrary</literal> check + as follows: + + </para> + + <sconstruct> + mylib_test_source_file = """ + #include &lt;mylib.h&gt; + int main(int argc, char **argv) + { + MyLibrary mylib(argc, argv); + return 0; + } + """ + + def CheckMyLibrary(context): + context.Message('Checking for MyLibrary... ') + result = context.TryLink(mylib_test_source_file, '.c') + context.Result(result) + return result + + env = Environment() + conf = Configure(env, custom_tests = {'CheckMyLibrary' : CheckMyLibrary}) + if not conf.CheckMyLibrary(): + print 'MyLibrary is not installed!' + Exit(1) + env = conf.Finish() + + # We would then add actual calls like Program() to build + # something using the "env" construction environment. + </sconstruct> + + <para> + + If MyLibrary is not installed on the system, + the output will look like: + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript file ... + Checking for MyLibrary... failed + MyLibrary is not installed! + </screen> + + <para> + + If MyLibrary is installed, + the output will look like: + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript file ... + Checking for MyLibrary... failed + scons: done reading SConscript + scons: Building targets ... + . + . + . + </screen> + + </section> + + <section> + <title>Not Configuring When Cleaning Targets</title> + + <para> + + Using multi-platform configuration + as described in the previous sections + will run the configuration commands + even when invoking + <userinput>scons -c</userinput> + to clean targets: + + </para> + + <screen> + % <userinput>scons -Q -c</userinput> + Checking for MyLibrary... yes + Removed foo.o + Removed foo + </screen> + + <para> + + Although running the platform checks + when removing targets doesn't hurt anything, + it's usually unnecessary. + You can avoid this by using the + &GetOption(); method to + check whether the <option>-c</option> (clean) + option has been invoked on the command line: + + </para> + + <sconstruct> + env = Environment() + if not env.GetOption('clean'): + conf = Configure(env, custom_tests = {'CheckMyLibrary' : CheckMyLibrary}) + if not conf.CheckMyLibrary(): + print 'MyLibrary is not installed!' + Exit(1) + env = conf.Finish() + </sconstruct> + + <screen> + % <userinput>scons -Q -c</userinput> + Removed foo.o + Removed foo + </screen> + + </section> + + <!-- + + <section> + <title>Controlling Configuration: the &config; Option</title> + + <para> + + XXX -D, -u and -U + + </para> + + </section> + + --> diff --git a/doc/user/sconf.xml b/doc/user/sconf.xml new file mode 100644 index 0000000..16ba534 --- /dev/null +++ b/doc/user/sconf.xml @@ -0,0 +1,486 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + &SCons; has integrated support for multi-platform build configuration + similar to that offered by GNU &Autoconf;, + such as + figuring out what libraries or header files + are available on the local system. + This section describes how to use + this &SCons; feature. + + </para> + + <note> + <para> + This chapter is still under development, + so not everything is explained as well as it should be. + See the &SCons; man page for additional information. + </para> + </note> + + <section> + <title>&Configure_Contexts;</title> + + <para> + + The basic framework for multi-platform build configuration + in &SCons; is to attach a &configure_context; to a + construction environment by calling the &Configure; function, + perform a number of checks for + libraries, functions, header files, etc., + and to then call the configure context's &Finish; method + to finish off the configuration: + + </para> + + <programlisting> + env = Environment() + conf = Configure(env) + # Checks for libraries, header files, etc. go here! + env = conf.Finish() + </programlisting> + + <para> + + &SCons; provides a number of basic checks, + as well as a mechanism for adding your own custom checks. + + </para> + + <para> + + Note that &SCons; uses its own dependency + mechanism to determine when a check + needs to be run--that is, + &SCons; does not run the checks + every time it is invoked, + but caches the values returned by previous checks + and uses the cached values unless something has changed. + This saves a tremendous amount + of developer time while working on + cross-platform build issues. + + </para> + + <para> + + The next sections describe + the basic checks that &SCons; supports, + as well as how to add your own custom checks. + + </para> + + </section> + + <section> + <title>Checking for the Existence of Header Files</title> + + <para> + + Testing the existence of a header file + requires knowing what language the header file is. + A configure context has a &CheckCHeader; method + that checks for the existence of a C header file: + + </para> + + <programlisting> + env = Environment() + conf = Configure(env) + if not conf.CheckCHeader('math.h'): + print 'Math.h must be installed!' + Exit(1) + if conf.CheckCHeader('foo.h'): + conf.env.Append('-DHAS_FOO_H') + env = conf.Finish() + </programlisting> + + <para> + + Note that you can choose to terminate + the build if a given header file doesn't exist, + or you can modify the construction environment + based on the existence of a header file. + + </para> + + <para> + + If you need to check for the existence + a C++ header file, + use the &CheckCXXHeader; method: + + </para> + + <programlisting> + env = Environment() + conf = Configure(env) + if not conf.CheckCXXHeader('vector.h'): + print 'vector.h must be installed!' + Exit(1) + env = conf.Finish() + </programlisting> + + </section> + + <section> + <title>Checking for the Availability of a Function</title> + + <para> + + Check for the availability of a specific function + using the &CheckFunc; method: + + </para> + + <programlisting> + env = Environment() + conf = Configure(env) + if not conf.CheckFunc('strcpy'): + print 'Did not find strcpy(), using local version' + conf.env.Append(CPPDEFINES = '-Dstrcpy=my_local_strcpy') + env = conf.Finish() + </programlisting> + + </section> + + <section> + <title>Checking for the Availability of a Library</title> + + <para> + + Check for the availability of a library + using the &CheckLib; method. + You only specify the basename of the library, + you don't need to add a <literal>lib</literal> + prefix or a <literal>.a</literal> or <literal>.lib</literal> suffix: + + </para> + + <programlisting> + env = Environment() + conf = Configure(env) + if not conf.CheckLib('m'): + print 'Did not find libm.a or m.lib, exiting!' + Exit(1) + env = conf.Finish() + </programlisting> + + <para> + + Because the ability to use a library successfully + often depends on having access to a header file + that describes the library's interface, + you can check for a library + <emphasis>and</emphasis> a header file + at the same time by using the + &CheckLibWithHeader; method: + + </para> + + <programlisting> + env = Environment() + conf = Configure(env) + if not conf.CheckLibWithHeader('m', 'math.h', 'c'): + print 'Did not find libm.a or m.lib, exiting!' + Exit(1) + env = conf.Finish() + </programlisting> + + <para> + + This is essentially shorthand for + separate calls to the &CheckHeader; and &CheckLib; + functions. + + </para> + + </section> + + <section> + <title>Checking for the Availability of a &typedef;</title> + + <para> + + Check for the availability of a &typedef; + by using the &CheckType; method: + + </para> + + <programlisting> + env = Environment() + conf = Configure(env) + if not conf.CheckType('off_t'): + print 'Did not find off_t typedef, assuming int' + conf.env.Append(CCFLAGS = '-Doff_t=int') + env = conf.Finish() + </programlisting> + + <para> + + You can also add a string that will be + placed at the beginning of the test file + that will be used to check for the &typedef;. + This provide a way to specify + files that must be included to find the &typedef;: + + </para> + + <programlisting> + env = Environment() + conf = Configure(env) + if not conf.CheckType('off_t', '#include <sys/types.h>\n'): + print 'Did not find off_t typedef, assuming int' + conf.env.Append(CCFLAGS = '-Doff_t=int') + env = conf.Finish() + </programlisting> + + </section> + + <section> + <title>Adding Your Own Custom Checks</title> + + <para> + + A custom check is a Python function + that checks for a certain condition to exist + on the running system, + usually using methods that &SCons; + supplies to take care of the details + of checking whether a compilation succeeds, + a link succeeds, + a program is runnable, + etc. + A simple custom check for the existence of + a specific library might look as follows: + + </para> + + <programlisting> + mylib_test_source_file = """ + #include <mylib.h> + int main(int argc, char **argv) + { + MyLibrary mylib(argc, argv); + return 0; + } + """ + + def CheckMyLibrary(context): + context.Message('Checking for MyLibrary...') + result = context.TryLink(mylib_test_source_file, '.c') + context.Result(result) + return result + </programlisting> + + <para> + + The &Message; and &Result; methods + should typically begin and end a custom check to + let the user know what's going on: + the &Message; call prints the + specified message (with no trailing newline) + and the &Result; call prints + <literal>yes</literal> if the check succeeds and + <literal>no</literal> if it doesn't. + The &TryLink; method + actually tests for whether the + specified program text + will successfully link. + + </para> + + <para> + + (Note that a custom check can modify + its check based on any arguments you + choose to pass it, + or by using or modifying the configure context environment + in the <literal>context.env</literal> attribute.) + + </para> + + <para> + + This custom check function is + then attached to the &configure_context; + by passing a dictionary + to the &Configure; call + that maps a name of the check + to the underlying function: + + </para> + + <programlisting> + env = Environment() + conf = Configure(env, custom_tests = {'CheckMyLibrary' : CheckMyLibrary}) + </programlisting> + + <para> + + You'll typically want to make + the check and the function name the same, + as we've done here, + to avoid potential confusion. + + </para> + + <para> + + We can then put these pieces together + and actually call the <literal>CheckMyLibrary</literal> check + as follows: + + </para> + + <programlisting> + mylib_test_source_file = """ + #include <mylib.h> + int main(int argc, char **argv) + { + MyLibrary mylib(argc, argv); + return 0; + } + """ + + def CheckMyLibrary(context): + context.Message('Checking for MyLibrary... ') + result = context.TryLink(mylib_test_source_file, '.c') + context.Result(result) + return result + + env = Environment() + conf = Configure(env, custom_tests = {'CheckMyLibrary' : CheckMyLibrary}) + if not conf.CheckMyLibrary(): + print 'MyLibrary is not installed!' + Exit(1) + env = conf.Finish() + + # We would then add actual calls like Program() to build + # something using the "env" construction environment. + </programlisting> + + <para> + + If MyLibrary is not installed on the system, + the output will look like: + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript file ... + Checking for MyLibrary... failed + MyLibrary is not installed! + </screen> + + <para> + + If MyLibrary is installed, + the output will look like: + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript file ... + Checking for MyLibrary... failed + scons: done reading SConscript + scons: Building targets ... + . + . + . + </screen> + + </section> + + <section> + <title>Not Configuring When Cleaning Targets</title> + + <para> + + Using multi-platform configuration + as described in the previous sections + will run the configuration commands + even when invoking + <userinput>scons -c</userinput> + to clean targets: + + </para> + + <screen> + % <userinput>scons -Q -c</userinput> + Checking for MyLibrary... yes + Removed foo.o + Removed foo + </screen> + + <para> + + Although running the platform checks + when removing targets doesn't hurt anything, + it's usually unnecessary. + You can avoid this by using the + &GetOption;(); method to + check whether the <option>-c</option> (clean) + option has been invoked on the command line: + + </para> + + <programlisting> + env = Environment() + if not env.GetOption('clean'): + conf = Configure(env, custom_tests = {'CheckMyLibrary' : CheckMyLibrary}) + if not conf.CheckMyLibrary(): + print 'MyLibrary is not installed!' + Exit(1) + env = conf.Finish() + </programlisting> + + <screen> + % <userinput>scons -Q -c</userinput> + Removed foo.o + Removed foo + </screen> + + </section> + + <!-- + + <section> + <title>Controlling Configuration: the &config; Option</title> + + <para> + + XXX -D, -u and -U + + </para> + + </section> + + --> diff --git a/doc/user/separate.in b/doc/user/separate.in new file mode 100644 index 0000000..edc6da8 --- /dev/null +++ b/doc/user/separate.in @@ -0,0 +1,540 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + It's often useful to keep any built files completely + separate from the source files. + In &SCons;, this is usually done by creating one or more separate + <emphasis>variant directory trees</emphasis> + that are used to hold the built objects files, libraries, + and executable programs, etc. + for a specific flavor, or variant, of build. + &SCons; provides two ways to do this, + one through the &SConscript; function that we've already seen, + and the second through a more flexible &VariantDir; function. + + </para> + + <para> + + One historical note: the &VariantDir; function + used to be called &BuildDir;. + That name is still supported + but has been deprecated + because the &SCons; functionality + differs from the model of a "build directory" + implemented by other build systems like the GNU Autotools. + + </para> + + <section> + <title>Specifying a Variant Directory Tree as Part of an &SConscript; Call</title> + + <para> + + The most straightforward way to establish a variant directory tree + uses the fact that the usual way to + set up a build hierarchy is to have an + &SConscript; file in the source subdirectory. + If you then pass a &variant_dir; argument to the + &SConscript; function call: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + SConscript('src/SConscript', variant_dir='build') + </file> + <file name="src/SConscript"> + env = Environment() + env.Program('hello.c') + </file> + <file name="src/hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + &SCons; will then build all of the files in + the &build; subdirectory: + + </para> + + <scons_output example="ex1"> + <scons_output_command>ls src</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>ls build</scons_output_command> + </scons_output> + + <para> + + But wait a minute--what's going on here? + &SCons; created the object file + <filename>build/hello.o</filename> + in the &build; subdirectory, + as expected. + But even though our &hello_c; file lives in the &src; subdirectory, + &SCons; has actually compiled a + <filename>build/hello.c</filename> file + to create the object file. + + </para> + + <para> + + What's happened is that &SCons; has <emphasis>duplicated</emphasis> + the &hello_c; file from the &src; subdirectory + to the &build; subdirectory, + and built the program from there. + The next section explains why &SCons; does this. + + </para> + + </section> + + <section> + <title>Why &SCons; Duplicates Source Files in a Variant Directory Tree</title> + + <para> + + &SCons; duplicates source files in variant directory trees + because it's the most straightforward way to guarantee a correct build + <emphasis>regardless of include-file directory paths, + relative references between files, + or tool support for putting files in different locations</emphasis>, + and the &SCons; philosophy is to, by default, + guarantee a correct build in all cases. + + </para> + + <para> + + The most direct reason to duplicate source files + in variant directories + is simply that some tools (mostly older versions) + are written to only build their output files + in the same directory as the source files. + In this case, the choices are either + to build the output file in the source directory + and move it to the variant directory, + or to duplicate the source files in the variant directory. + + </para> + + <para> + + Additionally, + relative references between files + can cause problems if we don't + just duplicate the hierarchy of source files + in the variant directory. + You can see this at work in + use of the C preprocessor <literal>#include</literal> + mechanism with double quotes, not angle brackets: + + </para> + + <sconstruct> + #include "file.h" + </sconstruct> + + <para> + + The <emphasis>de facto</emphasis> standard behavior + for most C compilers in this case + is to first look in the same directory + as the source file that contains the <literal>#include</literal> line, + then to look in the directories in the preprocessor search path. + Add to this that the &SCons; implementation of + support for code repositories + (described below) + means not all of the files + will be found in the same directory hierarchy, + and the simplest way to make sure + that the right include file is found + is to duplicate the source files into the variant directory, + which provides a correct build + regardless of the original location(s) of the source files. + + </para> + + <para> + + Although source-file duplication guarantees a correct build + even in these end-cases, + it <emphasis>can</emphasis> usually be safely disabled. + The next section describes + how you can disable the duplication of source files + in the variant directory. + + </para> + + </section> + + <section> + <title>Telling &SCons; to Not Duplicate Source Files in the Variant Directory Tree</title> + + <para> + + In most cases and with most tool sets, + &SCons; can place its target files in a build subdirectory + <emphasis>without</emphasis> + duplicating the source files + and everything will work just fine. + You can disable the default &SCons; behavior + by specifying <literal>duplicate=0</literal> + when you call the &SConscript; function: + + </para> + + <sconstruct> + SConscript('src/SConscript', variant_dir='build', duplicate=0) + </sconstruct> + + <para> + + When this flag is specified, + &SCons; uses the variant directory + like most people expect--that is, + the output files are placed in the variant directory + while the source files stay in the source directory: + + </para> + + <screen> + % <userinput>ls src</userinput> + SConscript + hello.c + % <userinput>scons -Q</userinput> + cc -c src/hello.c -o build/hello.o + cc -o build/hello build/hello.o + % <userinput>ls build</userinput> + hello + hello.o + </screen> + + </section> + + <section> + <title>The &VariantDir; Function</title> + + <para> + + Use the &VariantDir; function to establish that target + files should be built in a separate directory + from the source files: + + </para> + + <scons_example name="ex_builddir"> + <file name="SConstruct" printme="1"> + VariantDir('build', 'src') + env = Environment() + env.Program('build/hello.c') + </file> + <file name="src/hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + Note that when you're not using + an &SConscript; file in the &src; subdirectory, + you must actually specify that + the program must be built from + the <filename>build/hello.c</filename> + file that &SCons; will duplicate in the + &build; subdirectory. + + </para> + + <para> + + When using the &VariantDir; function directly, + &SCons; still duplicates the source files + in the variant directory by default: + + </para> + + <scons_output example="ex_builddir"> + <scons_output_command>ls src</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>ls build</scons_output_command> + </scons_output> + + <para> + + You can specify the same <literal>duplicate=0</literal> argument + that you can specify for an &SConscript; call: + + </para> + + <scons_example name="ex_duplicate_0"> + <file name="SConstruct" printme="1"> + VariantDir('build', 'src', duplicate=0) + env = Environment() + env.Program('build/hello.c') + </file> + <file name="src/hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + In which case &SCons; + will disable duplication of the source files: + + </para> + + <scons_output example="ex_duplicate_0"> + <scons_output_command>ls src</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>ls build</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Using &VariantDir; With an &SConscript; File</title> + + <para> + + Even when using the &VariantDir; function, + it's much more natural to use it with + a subsidiary &SConscript; file. + For example, if the + <filename>src/SConscript</filename> + looks like this: + + </para> + + <scons_example name="example_builddir_sconscript"> + <file name="SConstruct"> + VariantDir('build', 'src') + SConscript('build/SConscript') + </file> + <file name="src/SConscript" printme="1"> + env = Environment() + env.Program('hello.c') + </file> + <file name="src/hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + Then our &SConstruct; file could look like: + + </para> + + <scons_example_file example="example_builddir_sconscript" name="SConstruct"> + </scons_example_file> + + <para> + + Yielding the following output: + + </para> + + <scons_output example="example_builddir_sconscript"> + <scons_output_command>ls src</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>ls build</scons_output_command> + </scons_output> + + <para> + + Notice that this is completely equivalent + to the use of &SConscript; that we + learned about in the previous section. + + </para> + + </section> + + <section> + <title>Using &Glob; with &VariantDir;</title> + + <para> + + The &Glob; file name pattern matching function + works just as usual when using &VariantDir;. + For example, if the + <filename>src/SConscript</filename> + looks like this: + + </para> + + <scons_example name="example_glob_builddir_sconscript"> + <file name="SConstruct"> + VariantDir('build', 'src') + SConscript('build/SConscript') + </file> + <file name="src/SConscript" printme="1"> + env = Environment() + env.Program('hello', Glob('*.c')) + </file> + <file name="src/f1.c"> + #include "f2.h" + int main() { printf(f2()); } + </file> + <file name="src/f2.c"> + const char * f2() { return("Hello, world!\n"); } + </file> + <file name="src/f2.h"> + const char * f2(); + </file> + </scons_example> + + <para> + + Then with the same &SConstruct; file as in the previous section, + and source files <filename>f1.c</filename> + and <filename>f2.c</filename> in src, + we would see the following output: + + </para> + + <scons_output example="example_glob_builddir_sconscript"> + <scons_output_command>ls src</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>ls build</scons_output_command> + </scons_output> + + <para> + + The &Glob; function returns Nodes in the + <filename>build/</filename> tree, as you'd expect. + + </para> + + </section> + + <!-- + + <section> + <title>Why You'd Want to Call &VariantDir; Instead of &SConscript;</title> + + <para> + + XXX why call VariantDir() instead of SConscript(variant_dir=) + + </para> + + </section> + + --> diff --git a/doc/user/separate.xml b/doc/user/separate.xml new file mode 100644 index 0000000..fd5bdf0 --- /dev/null +++ b/doc/user/separate.xml @@ -0,0 +1,520 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + It's often useful to keep any built files completely + separate from the source files. + In &SCons;, this is usually done by creating one or more separate + <emphasis>variant directory trees</emphasis> + that are used to hold the built objects files, libraries, + and executable programs, etc. + for a specific flavor, or variant, of build. + &SCons; provides two ways to do this, + one through the &SConscript; function that we've already seen, + and the second through a more flexible &VariantDir; function. + + </para> + + <para> + + One historical note: the &VariantDir; function + used to be called &BuildDir;. + That name is still supported + but has been deprecated + because the &SCons; functionality + differs from the model of a "build directory" + implemented by other build systems like the GNU Autotools. + + </para> + + <section> + <title>Specifying a Variant Directory Tree as Part of an &SConscript; Call</title> + + <para> + + The most straightforward way to establish a variant directory tree + uses the fact that the usual way to + set up a build hierarchy is to have an + &SConscript; file in the source subdirectory. + If you then pass a &variant_dir; argument to the + &SConscript; function call: + + </para> + + <programlisting> + SConscript('src/SConscript', variant_dir='build') + </programlisting> + + <para> + + &SCons; will then build all of the files in + the &build; subdirectory: + + </para> + + <screen> + % <userinput>ls src</userinput> + SConscript hello.c + % <userinput>scons -Q</userinput> + cc -o build/hello.o -c build/hello.c + cc -o build/hello build/hello.o + % <userinput>ls build</userinput> + SConscript hello hello.c hello.o + </screen> + + <para> + + But wait a minute--what's going on here? + &SCons; created the object file + <filename>build/hello.o</filename> + in the &build; subdirectory, + as expected. + But even though our &hello_c; file lives in the &src; subdirectory, + &SCons; has actually compiled a + <filename>build/hello.c</filename> file + to create the object file. + + </para> + + <para> + + What's happened is that &SCons; has <emphasis>duplicated</emphasis> + the &hello_c; file from the &src; subdirectory + to the &build; subdirectory, + and built the program from there. + The next section explains why &SCons; does this. + + </para> + + </section> + + <section> + <title>Why &SCons; Duplicates Source Files in a Variant Directory Tree</title> + + <para> + + &SCons; duplicates source files in variant directory trees + because it's the most straightforward way to guarantee a correct build + <emphasis>regardless of include-file directory paths, + relative references between files, + or tool support for putting files in different locations</emphasis>, + and the &SCons; philosophy is to, by default, + guarantee a correct build in all cases. + + </para> + + <para> + + The most direct reason to duplicate source files + in variant directories + is simply that some tools (mostly older versions) + are written to only build their output files + in the same directory as the source files. + In this case, the choices are either + to build the output file in the source directory + and move it to the variant directory, + or to duplicate the source files in the variant directory. + + </para> + + <para> + + Additionally, + relative references between files + can cause problems if we don't + just duplicate the hierarchy of source files + in the variant directory. + You can see this at work in + use of the C preprocessor <literal>#include</literal> + mechanism with double quotes, not angle brackets: + + </para> + + <programlisting> + #include "file.h" + </programlisting> + + <para> + + The <emphasis>de facto</emphasis> standard behavior + for most C compilers in this case + is to first look in the same directory + as the source file that contains the <literal>#include</literal> line, + then to look in the directories in the preprocessor search path. + Add to this that the &SCons; implementation of + support for code repositories + (described below) + means not all of the files + will be found in the same directory hierarchy, + and the simplest way to make sure + that the right include file is found + is to duplicate the source files into the variant directory, + which provides a correct build + regardless of the original location(s) of the source files. + + </para> + + <para> + + Although source-file duplication guarantees a correct build + even in these end-cases, + it <emphasis>can</emphasis> usually be safely disabled. + The next section describes + how you can disable the duplication of source files + in the variant directory. + + </para> + + </section> + + <section> + <title>Telling &SCons; to Not Duplicate Source Files in the Variant Directory Tree</title> + + <para> + + In most cases and with most tool sets, + &SCons; can place its target files in a build subdirectory + <emphasis>without</emphasis> + duplicating the source files + and everything will work just fine. + You can disable the default &SCons; behavior + by specifying <literal>duplicate=0</literal> + when you call the &SConscript; function: + + </para> + + <programlisting> + SConscript('src/SConscript', variant_dir='build', duplicate=0) + </programlisting> + + <para> + + When this flag is specified, + &SCons; uses the variant directory + like most people expect--that is, + the output files are placed in the variant directory + while the source files stay in the source directory: + + </para> + + <screen> + % <userinput>ls src</userinput> + SConscript + hello.c + % <userinput>scons -Q</userinput> + cc -c src/hello.c -o build/hello.o + cc -o build/hello build/hello.o + % <userinput>ls build</userinput> + hello + hello.o + </screen> + + </section> + + <section> + <title>The &VariantDir; Function</title> + + <para> + + Use the &VariantDir; function to establish that target + files should be built in a separate directory + from the source files: + + </para> + + <programlisting> + VariantDir('build', 'src') + env = Environment() + env.Program('build/hello.c') + </programlisting> + + <para> + + Note that when you're not using + an &SConscript; file in the &src; subdirectory, + you must actually specify that + the program must be built from + the <filename>build/hello.c</filename> + file that &SCons; will duplicate in the + &build; subdirectory. + + </para> + + <para> + + When using the &VariantDir; function directly, + &SCons; still duplicates the source files + in the variant directory by default: + + </para> + + <screen> + % <userinput>ls src</userinput> + hello.c + % <userinput>scons -Q</userinput> + cc -o build/hello.o -c build/hello.c + cc -o build/hello build/hello.o + % <userinput>ls build</userinput> + hello hello.c hello.o + </screen> + + <para> + + You can specify the same <literal>duplicate=0</literal> argument + that you can specify for an &SConscript; call: + + </para> + + <programlisting> + VariantDir('build', 'src', duplicate=0) + env = Environment() + env.Program('build/hello.c') + </programlisting> + + <para> + + In which case &SCons; + will disable duplication of the source files: + + </para> + + <screen> + % <userinput>ls src</userinput> + hello.c + % <userinput>scons -Q</userinput> + cc -o build/hello.o -c src/hello.c + cc -o build/hello build/hello.o + % <userinput>ls build</userinput> + hello hello.o + </screen> + + </section> + + <section> + <title>Using &VariantDir; With an &SConscript; File</title> + + <para> + + Even when using the &VariantDir; function, + it's much more natural to use it with + a subsidiary &SConscript; file. + For example, if the + <filename>src/SConscript</filename> + looks like this: + + </para> + + <programlisting> + env = Environment() + env.Program('hello.c') + </programlisting> + + <para> + + Then our &SConstruct; file could look like: + + </para> + + + <programlisting> + VariantDir('build', 'src') + SConscript('build/SConscript') + </programlisting> + + <para> + + Yielding the following output: + + </para> + + <screen> + % <userinput>ls src</userinput> + SConscript hello.c + % <userinput>scons -Q</userinput> + cc -o build/hello.o -c build/hello.c + cc -o build/hello build/hello.o + % <userinput>ls build</userinput> + SConscript hello hello.c hello.o + </screen> + + <para> + + Notice that this is completely equivalent + to the use of &SConscript; that we + learned about in the previous section. + + </para> + + </section> + + <section> + <title>Using &Glob; with &VariantDir;</title> + + <para> + + The &Glob; file name pattern matching function + works just as usual when using &VariantDir;. + For example, if the + <filename>src/SConscript</filename> + looks like this: + + </para> + + <programlisting> + env = Environment() + env.Program('hello', Glob('*.c')) + </programlisting> + + <para> + + Then with the same &SConstruct; file as in the previous section, + and source files <filename>f1.c</filename> + and <filename>f2.c</filename> in src, + we would see the following output: + + </para> + + <screen> + % <userinput>ls src</userinput> + SConscript f1.c f2.c f2.h + % <userinput>scons -Q</userinput> + cc -o build/f1.o -c build/f1.c + cc -o build/f2.o -c build/f2.c + cc -o build/hello build/f1.o build/f2.o + % <userinput>ls build</userinput> + SConscript f1.c f1.o f2.c f2.h f2.o hello + </screen> + + <para> + + The &Glob; function returns Nodes in the + <filename>build/</filename> tree, as you'd expect. + + </para> + + </section> + + <!-- + + <section> + <title>Why You'd Want to Call &VariantDir; Instead of &SConscript;</title> + + <para> + + XXX why call VariantDir() instead of SConscript(variant_dir=) + + </para> + + </section> + + --> diff --git a/doc/user/sideeffect.in b/doc/user/sideeffect.in new file mode 100644 index 0000000..58c7306 --- /dev/null +++ b/doc/user/sideeffect.in @@ -0,0 +1,216 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + If &SCons; is unaware that a build step produces an extra file, + the &SideEffect; method can be used to identify it, + so that the file can be used as a dependency in subsequent build steps. + However, the primary use for the &SideEffect; method + is to prevent two build steps from simultaneously modifying the same file. + + </para> + + TODO: currently doesn't work due to issue #2154: + http://scons.tigris.org/issues/show_bug.cgi?id=2154 + + <para> + + If more than one build step creates or manipulates the same file, + it can cause unpleasant results if both build steps are run at the same time. + The shared file is declared as a side-effect of building the primary targets + and &SCons; will prevent the two build steps from running in parallel. + + </para> + + <para> + + In this example, the <filename>SConscript</filename> uses + &SideEffect; to inform &SCons; about the additional output file. + + </para> + + <scons_example name="SideEffectSimple"> + <file name="SConstruct" printme="1"> + env = Environment() + f2 = env.Command('file2', 'log', Copy('$TARGET', '$SOURCE')) + f1 = env.Command('file1', [], + 'echo >$TARGET data1; echo >log updated file1')) + env.SideEffect('log', env.Command('file1', [], + 'echo >$TARGET data1; echo >log updated file1')) + </file> + </scons_example> + + <para> + + Even when run in parallel mode, &SCons; will run the two steps in order: + + </para> + + <scons_output example="SideEffectSimple"> + <scons_output_command>scons -Q --jobs=2</scons_output_command> + </scons_output> + + --> + + <para> + + Sometimes a program the you need to call + to build a target file + will also update another file, + such as a log file describing what the program + does while building the target. + For example, we the folowing configuration + would have &SCons; invoke a hypothetical + script named <application>build</application> + (in the local directory) + with command-line arguments that write + log information to a common + <filename>logfile.txt</filename> file: + + </para> + + <screen> + env = Environment() + env.Command('file1.out', 'file.in', + './build --log logfile.txt $SOURCE $TARGET') + env.Command('file2.out', 'file.in', + './build --log logfile.txt $SOURCE $TARGET') + <screen> + + <para> + + This can cause problems when running + the build in parallel if + &SCons; decides to update both targets + by running both program invocations at the same time. + The multiple program invocations + may interfere with each other + writing to the common log file, + leading at best to intermixed output in the log file, + and at worst to an actual failed build + (on a system like Windows, for example, + where only one process at a time can open the log file for writing). + + </para> + + <para> + + We can make sure that &SCons; does not + run these <application>build</application> + commands at the same time + by using the &SideEffect; function + to specify that updating + the <filename>logfile.txt</filename> file + is a side effect of building the specified + <filename>file1</filename> + and + <filename>file2</filename> + target files: + + </para> + + <scons_example name="SideEffectShared"> + <file name="SConstruct" printme="1"> + env = Environment() + f1 = env.Command('file1.out', 'file1.in', + './build --log logfile.txt $SOURCE $TARGET') + f2 = env.Command('file2.out', 'file2.in', + './build --log logfile.txt $SOURCE $TARGET') + env.SideEffect('logfile.txt', f1 + f2) + </file> + <file name="file1.in">file1.in</file> + <file name="file2.in">file2.in</file> + <file name="build" chmod="0755"> + cat + </file> + </scons_example> + + <para> + + </para> + + <para> + + This makes sure the the two + <application>./build</application> steps are run sequentially, + even withthe <filename>--jobs=2</filename> in the command line: + + </para> + + <scons_output example="SideEffectShared"> + <scons_output_command>scons -Q --jobs=2</scons_output_command> + </scons_output> + + <para> + + The &SideEffect; function can be called multiple + times for the same side-effect file. + Additionally, the name used as a &SideEffect; does not + even need to actually exist as a file on disk. + &SCons; will still make sure + that the relevant targets + will be executed sequentially, not in parallel: + + </para> + + <scons_example name="SideEffectParallel"> + <file name="SConstruct" printme="1"> + env = Environment() + f1 = env.Command('file1.out', [], 'echo >$TARGET data1') + env.SideEffect('not_really_updated', f1) + f2 = env.Command('file2.out', [], 'echo >$TARGET data2') + env.SideEffect('not_really_updated', f2) + </file> + </scons_example> + + <scons_output example="SideEffectParallel"> + <scons_output_command>scons -Q --jobs=2</scons_output_command> + </scons_output> + + <para> + + Note that it might be tempting to + use &SideEffect; for additional target files + that a command produces. + For example, versions the Microsoft Visual C/C++ compiler + produce a <filename>foo.ilk</filename> + alongside compiling <filename>foo.obj</filename> file. + Specifying <filename>foo.ilk</filename> as a + side-effect of <filename>foo.obj</filename> + is <emphasis>not</emphasis> a recommended use of &SideEffect;, + because &SCons; handle side-effect files + slightly differently in its analysis of the dependency graph. + When a command produces multiple output files, + they should be specified as multiple targets of + the call to the relevant builder function, + and the &SideEffect; function itself should really only be used + when it's important to ensure that commands are not executed in parallel, + such as when a "peripheral" file (such as a log file) + may actually updated by more than one command invocation. + + </para> diff --git a/doc/user/sideeffect.xml b/doc/user/sideeffect.xml new file mode 100644 index 0000000..df62eca --- /dev/null +++ b/doc/user/sideeffect.xml @@ -0,0 +1,211 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + If &SCons; is unaware that a build step produces an extra file, + the &SideEffect; method can be used to identify it, + so that the file can be used as a dependency in subsequent build steps. + However, the primary use for the &SideEffect; method + is to prevent two build steps from simultaneously modifying the same file. + + </para> + + TODO: currently doesn't work due to issue #2154: + http://scons.tigris.org/issues/show_bug.cgi?id=2154 + + <para> + + If more than one build step creates or manipulates the same file, + it can cause unpleasant results if both build steps are run at the same time. + The shared file is declared as a side-effect of building the primary targets + and &SCons; will prevent the two build steps from running in parallel. + + </para> + + <para> + + In this example, the <filename>SConscript</filename> uses + &SideEffect; to inform &SCons; about the additional output file. + + </para> + + <scons_example name="SideEffectSimple"> + <file name="SConstruct" printme="1"> + env = Environment() + f2 = env.Command('file2', 'log', Copy('$TARGET', '$SOURCE')) + f1 = env.Command('file1', [], + 'echo >$TARGET data1; echo >log updated file1')) + env.SideEffect('log', env.Command('file1', [], + 'echo >$TARGET data1; echo >log updated file1')) + </file> + </scons_example> + + <para> + + Even when run in parallel mode, &SCons; will run the two steps in order: + + </para> + + <scons_output example="SideEffectSimple"> + <scons_output_command>scons -Q --jobs=2</scons_output_command> + </scons_output> + + --> + + <para> + + Sometimes a program the you need to call + to build a target file + will also update another file, + such as a log file describing what the program + does while building the target. + For example, we the folowing configuration + would have &SCons; invoke a hypothetical + script named <application>build</application> + (in the local directory) + with command-line arguments that write + log information to a common + <filename>logfile.txt</filename> file: + + </para> + + <screen> + env = Environment() + env.Command('file1.out', 'file.in', + './build --log logfile.txt $SOURCE $TARGET') + env.Command('file2.out', 'file.in', + './build --log logfile.txt $SOURCE $TARGET') + <screen> + + <para> + + This can cause problems when running + the build in parallel if + &SCons; decides to update both targets + by running both program invocations at the same time. + The multiple program invocations + may interfere with each other + writing to the common log file, + leading at best to intermixed output in the log file, + and at worst to an actual failed build + (on a system like Windows, for example, + where only one process at a time can open the log file for writing). + + </para> + + <para> + + We can make sure that &SCons; does not + run these <application>build</application> + commands at the same time + by using the &SideEffect; function + to specify that updating + the <filename>logfile.txt</filename> file + is a side effect of building the specified + <filename>file1</filename> + and + <filename>file2</filename> + target files: + + </para> + + <programlisting> + env = Environment() + f1 = env.Command('file1.out', 'file1.in', + './build --log logfile.txt $SOURCE $TARGET') + f2 = env.Command('file2.out', 'file2.in', + './build --log logfile.txt $SOURCE $TARGET') + env.SideEffect('logfile.txt', f1 + f2) + </programlisting> + + <para> + + </para> + + <para> + + This makes sure the the two + <application>./build</application> steps are run sequentially, + even withthe <filename>--jobs=2</filename> in the command line: + + </para> + + <screen> + % <userinput>scons -Q --jobs=2</userinput> + ./build --log logfile.txt file1.in file1.out + ./build --log logfile.txt file2.in file2.out + </screen> + + <para> + + The &SideEffect; function can be called multiple + times for the same side-effect file. + Additionally, the name used as a &SideEffect; does not + even need to actually exist as a file on disk. + &SCons; will still make sure + that the relevant targets + will be executed sequentially, not in parallel: + + </para> + + <programlisting> + env = Environment() + f1 = env.Command('file1.out', [], 'echo >$TARGET data1') + env.SideEffect('not_really_updated', f1) + f2 = env.Command('file2.out', [], 'echo >$TARGET data2') + env.SideEffect('not_really_updated', f2) + </programlisting> + + <screen> + % <userinput>scons -Q --jobs=2</userinput> + echo > file1.out data1 + echo > file2.out data2 + </screen> + + <para> + + Note that it might be tempting to + use &SideEffect; for additional target files + that a command produces. + For example, versions the Microsoft Visual C/C++ compiler + produce a <filename>foo.ilk</filename> + alongside compiling <filename>foo.obj</filename> file. + Specifying <filename>foo.ilk</filename> as a + side-effect of <filename>foo.obj</filename> + is <emphasis>not</emphasis> a recommended use of &SideEffect;, + because &SCons; handle side-effect files + slightly differently in its analysis of the dependency graph. + When a command produces multiple output files, + they should be specified as multiple targets of + the call to the relevant builder function, + and the &SideEffect; function itself should really only be used + when it's important to ensure that commands are not executed in parallel, + such as when a "peripheral" file (such as a log file) + may actually updated by more than one command invocation. + + </para> diff --git a/doc/user/simple.in b/doc/user/simple.in new file mode 100644 index 0000000..4d42934 --- /dev/null +++ b/doc/user/simple.in @@ -0,0 +1,517 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + In this chapter, + you will see several examples of + very simple build configurations using &SCons;, + which will demonstrate how easy + it is to use &SCons; to + build programs from several different programming languages + on different types of systems. + + </para> + + <section> + <title>Building Simple C / C++ Programs</title> + + <para> + + Here's the famous "Hello, World!" program in C: + + </para> + + <programlisting> + int + main() + { + printf("Hello, world!\n"); + } + </programlisting> + + <para> + + And here's how to build it using &SCons;. + Enter the following into a file named &SConstruct;: + + </para> + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + Program('hello.c') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + This minimal configuration file gives + &SCons; two pieces of information: + what you want to build + (an executable program), + and the input file from + which you want it built + (the <filename>hello.c</filename> file). + &b-link-Program; is a <firstterm>builder_method</firstterm>, + a Python call that tells &SCons; that you want to build an + executable program. + + </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: + + </para> + + <scons_output example="ex1" os="posix"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + On a Windows system with the Microsoft Visual C++ compiler, + you'll see something like: + + </para> + + <scons_output example="ex1" os="win32"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + First, notice that you only need + to specify the name of the source file, + and that &SCons; correctly deduces the names of + the object and executable files to be built + from the base of the source file name. + + </para> + + <para> + + Second, notice that the same input &SConstruct; file, + without any changes, + generates the correct 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. + This is a simple example of how &SCons; + makes it extremely easy to + write portable software builds. + + </para> + + <para> + + (Note that we won't provide duplicate side-by-side + POSIX and Windows output for all of the examples in this guide; + just keep in mind that, unless otherwise specified, + any of the examples should work equally well on both types of systems.) + + </para> + + </section> + + <section> + <title>Building Object Files</title> + + <para> + + The &b-link-Program; builder method is only one of + many builder methods that &SCons; provides + to build different types of files. + Another is the &b-link-Object; builder method, + which tells &SCons; to build an object file + from the specified source file: + + </para> + + <scons_example name="Object"> + <file name="SConstruct" printme="1"> + Object('hello.c') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <para> + + Now when you run the &scons; command to build the program, + it will build just the &hello_o; object file on a POSIX system: + + </para> + + <scons_output example="Object" os="posix"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + And just the &hello_obj; object file + on a Windows system (with the Microsoft Visual C++ compiler): + + </para> + + <scons_output example="Object" os="win32"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Simple Java Builds</title> + + <para> + + &SCons; also makes building with Java extremely easy. + Unlike the &b-link-Program; and &b-link-Object; builder methods, + however, the &b-link-Java; builder method + requires that you specify + the name of a destination directory in which + you want the class files placed, + followed by the source directory + in which the <filename>.java</filename> files live: + + </para> + + <scons_example name="java"> + <file name="SConstruct" printme="1"> + Java('classes', 'src') + </file> + <file name="src/hello.java"> + public class Example1 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + </file> + </scons_example> + + <para> + + If the <filename>src</filename> directory + contains a single <filename>hello.java</filename> file, + then the output from running the &scons; command + would look something like this + (on a POSIX system): + + </para> + + <scons_output example="java" os="posix"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + We'll cover Java builds in more detail, + including building Java archive (<filename>.jar</filename>) + and other types of file, + in <xref linkend="chap-java"></xref>. + + </para> + + </section> + + <section> + <title>Cleaning Up After a Build</title> + + <para> + + When using &SCons;, it is unnecessary to add special + commands or target names to clean up after a build. + Instead, you simply use the + <literal>-c</literal> or <literal>--clean</literal> + option when you invoke &SCons;, + and &SCons; removes the appropriate built files. + So if we build our example above + and then invoke <literal>scons -c</literal> + afterwards, the output on POSIX looks like: + + </para> + + <scons_example name="clean"> + <file name="SConstruct"> + Program('hello.c') + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + </scons_example> + + <scons_output example="clean" os="posix"> + <scons_output_command>scons</scons_output_command> + <scons_output_command>scons -c</scons_output_command> + </scons_output> + + <para> + + And the output on Windows looks like: + + </para> + + <scons_output example="clean" os="win32"> + <scons_output_command>scons</scons_output_command> + <scons_output_command>scons -c</scons_output_command> + </scons_output> + + <para> + + Notice that &SCons; changes its output to tell you that it + is <literal>Cleaning targets ...</literal> and + <literal>done cleaning targets.</literal> + + </para> + + </section> + + <section> + <title>The &SConstruct; File</title> + + <para> + + 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> + <title>&SConstruct; Files Are Python Scripts</title> + + <para> + + There is, however, 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. + This User's Guide will introduce you step-by-step + to the relatively small amount of Python you'll + need to know to be able to use &SCons; effectively. + And Python is very easy to learn. + + </para> + + <para> + + One aspect of using Python as the + scripting language is 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> + # Arrange to build the "hello" program. + Program('hello.c') # "hello.c" is the source file. + </programlisting> + + <para> + + You'll see throughout the remainder of this Guide + 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> + + </section> + + <section> + <title>&SCons; Functions Are Order-Independent</title> + + <para> + + One important way in which the &SConstruct; + file is not exactly like a normal Python script, + and is more like a &Makefile, + is that the order in which + the &SCons; functions are called in + the &SConstruct; file + does <emphasis>not</emphasis> + affect the order in which &SCons; + actually builds the programs and object files + you want it to build.<footnote> + <para>In programming parlance, + the &SConstruct; file is + <emphasis>declarative</emphasis>, + meaning you tell &SCons; what you want done + and let it figure out the order in which to do it, + rather than strictly <emphasis>imperative</emphasis>, + where you specify explicitly the order in + which to do things. + </para> + </footnote> + In other words, when you call the &b-link-Program; builder + (or any other builder method), + you're not telling &SCons; to build + the program at the instant the builder method is called. + Instead, you're telling &SCons; to build the program + that you want, for example, + a program built from a file named &hello_c;, + and it's up to &SCons; to build that program + (and any other files) whenever it's necessary. + (We'll learn more about how + &SCons; decides when building or rebuilding a file + is necessary in <xref linkend="chap-depends"></xref>, below.) + + </para> + + <para> + + &SCons; reflects this distinction between + <emphasis>calling a builder method like</emphasis> &b-Program; + and <emphasis>actually building the program</emphasis> + by printing the status messages that indicate + when it's "just reading" the &SConstruct; file, + and when it's actually building the target files. + This is to make it clear when &SCons; is + executing the Python statements that make up the &SConstruct; file, + and when &SCons; is actually executing the + commands or other actions to + build the necessary files. + + </para> + + <para> + + Let's clarify this with an example. + Python has a <literal>print</literal> statement that + prints a string of characters to the screen. + If we put <literal>print</literal> statements around + our calls to the &b-Program; builder method: + + </para> + + <scons_example name="declarative"> + <file name="SConstruct" printme="1"> + print "Calling Program('hello.c')" + Program('hello.c') + print "Calling Program('goodbye.c')" + Program('goodbye.c') + print "Finished calling Program()" + </file> + <file name="hello.c"> + int main() { printf("Hello, world!\n"); } + </file> + <file name="goodbye.c"> + int main() { printf("Goodbye, world!\n"); } + </file> + </scons_example> + + <para> + + Then when we execute &SCons;, + we see the output from the <literal>print</literal> + statements in between the messages about + reading the &SConscript; files, + indicating that that is when the + Python statements are being executed: + + </para> + + <scons_output example="declarative" os="posix"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + Notice also that &SCons; built the &goodbye; program first, + even though the "reading &SConscript" output + shows that we called <literal>Program('hello.c')</literal> + first in the &SConstruct; file. + + </para> + + </section> + + </section> + + <section> + <title>Making the &SCons; Output Less Verbose</title> + + <para> + + You've already seen how &SCons; prints + some messages about what it's doing, + surrounding the actual commands used to build the software: + + </para> + + <scons_output example="ex1" os="win32"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + These messages emphasize the + order in which &SCons; does its work: + all of the configuration files + (generically referred to as &SConscript; files) + are read and executed first, + and only then are the target files built. + Among other benefits, these messages help to distinguish between + errors that occur while the configuration files are read, + and errors that occur while targets are being built. + + </para> + + <para> + + One drawback, of course, is that these messages clutter the output. + Fortunately, they're easily disabled by using + the &Q; option when invoking &SCons;: + + </para> + + <scons_output example="ex1" os="win32"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Because we want this User's Guide to focus + on what &SCons; is actually doing, + we're going to use the &Q; option + to remove these messages from the + output of all the remaining examples in this Guide. + + </para> + + </section> diff --git a/doc/user/simple.xml b/doc/user/simple.xml new file mode 100644 index 0000000..598d44b --- /dev/null +++ b/doc/user/simple.xml @@ -0,0 +1,587 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + In this chapter, + you will see several examples of + very simple build configurations using &SCons;, + which will demonstrate how easy + it is to use &SCons; to + build programs from several different programming languages + on different types of systems. + + </para> + + <section> + <title>Building Simple C / C++ Programs</title> + + <para> + + Here's the famous "Hello, World!" program in C: + + </para> + + <programlisting> + int + main() + { + printf("Hello, world!\n"); + } + </programlisting> + + <para> + + And here's how to build it using &SCons;. + Enter the following into a file named &SConstruct;: + + </para> + + <programlisting> + Program('hello.c') + </programlisting> + + <para> + + This minimal configuration file gives + &SCons; two pieces of information: + what you want to build + (an executable program), + and the input file from + which you want it built + (the <filename>hello.c</filename> file). + &b-link-Program; is a <firstterm>builder_method</firstterm>, + a Python call that tells &SCons; that you want to build an + executable program. + + </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: + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + scons: done reading SConscript files. + scons: Building targets ... + cc -o hello.o -c hello.c + cc -o hello hello.o + scons: done building targets. + </screen> + + <para> + + On a Windows system with the Microsoft Visual C++ compiler, + you'll see something like: + + </para> + + <screen> + C:\><userinput>scons</userinput> + scons: Reading SConscript files ... + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + scons: done reading SConscript files. + scons: Building targets ... + cl /Fohello.obj /c hello.c /nologo + link /nologo /OUT:hello.exe hello.obj + scons: done building targets. + </screen> + + <para> + + First, notice that you only need + to specify the name of the source file, + and that &SCons; correctly deduces the names of + the object and executable files to be built + from the base of the source file name. + + </para> + + <para> + + Second, notice that the same input &SConstruct; file, + without any changes, + generates the correct 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. + This is a simple example of how &SCons; + makes it extremely easy to + write portable software builds. + + </para> + + <para> + + (Note that we won't provide duplicate side-by-side + POSIX and Windows output for all of the examples in this guide; + just keep in mind that, unless otherwise specified, + any of the examples should work equally well on both types of systems.) + + </para> + + </section> + + <section> + <title>Building Object Files</title> + + <para> + + The &b-link-Program; builder method is only one of + many builder methods that &SCons; provides + to build different types of files. + Another is the &b-link-Object; builder method, + which tells &SCons; to build an object file + from the specified source file: + + </para> + + <programlisting> + Object('hello.c') + </programlisting> + + <para> + + Now when you run the &scons; command to build the program, + it will build just the &hello_o; object file on a POSIX system: + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + scons: done reading SConscript files. + scons: Building targets ... + cc -o hello.o -c hello.c + scons: done building targets. + </screen> + + <para> + + And just the &hello_obj; object file + on a Windows system (with the Microsoft Visual C++ compiler): + + </para> + + <screen> + C:\><userinput>scons</userinput> + scons: Reading SConscript files ... + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + scons: done reading SConscript files. + scons: Building targets ... + cl /Fohello.obj /c hello.c /nologo + scons: done building targets. + </screen> + + </section> + + <section> + <title>Simple Java Builds</title> + + <para> + + &SCons; also makes building with Java extremely easy. + Unlike the &b-link-Program; and &b-link-Object; builder methods, + however, the &b-link-Java; builder method + requires that you specify + the name of a destination directory in which + you want the class files placed, + followed by the source directory + in which the <filename>.java</filename> files live: + + </para> + + <programlisting> + Java('classes', 'src') + </programlisting> + + <para> + + If the <filename>src</filename> directory + contains a single <filename>hello.java</filename> file, + then the output from running the &scons; command + would look something like this + (on a POSIX system): + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + scons: done reading SConscript files. + scons: Building targets ... + javac -d classes -sourcepath src src/hello.java + scons: done building targets. + </screen> + + <para> + + We'll cover Java builds in more detail, + including building Java archive (<filename>.jar</filename>) + and other types of file, + in <xref linkend="chap-java"></xref>. + + </para> + + </section> + + <section> + <title>Cleaning Up After a Build</title> + + <para> + + When using &SCons;, it is unnecessary to add special + commands or target names to clean up after a build. + Instead, you simply use the + <literal>-c</literal> or <literal>--clean</literal> + option when you invoke &SCons;, + and &SCons; removes the appropriate built files. + So if we build our example above + and then invoke <literal>scons -c</literal> + afterwards, the output on POSIX looks like: + + </para> + + + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + scons: done reading SConscript files. + scons: Building targets ... + cc -o hello.o -c hello.c + cc -o hello hello.o + scons: done building targets. + % <userinput>scons -c</userinput> + scons: Reading SConscript files ... + scons: done reading SConscript files. + scons: Cleaning targets ... + Removed hello.o + Removed hello + scons: done cleaning targets. + </screen> + + <para> + + And the output on Windows looks like: + + </para> + + <screen> + C:\><userinput>scons</userinput> + scons: Reading SConscript files ... + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + scons: done reading SConscript files. + scons: Building targets ... + cl /Fohello.obj /c hello.c /nologo + link /nologo /OUT:hello.exe hello.obj + scons: done building targets. + C:\><userinput>scons -c</userinput> + scons: Reading SConscript files ... + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + scons: done reading SConscript files. + scons: Cleaning targets ... + Removed hello.obj + Removed hello.exe + scons: done cleaning targets. + </screen> + + <para> + + Notice that &SCons; changes its output to tell you that it + is <literal>Cleaning targets ...</literal> and + <literal>done cleaning targets.</literal> + + </para> + + </section> + + <section> + <title>The &SConstruct; File</title> + + <para> + + 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> + <title>&SConstruct; Files Are Python Scripts</title> + + <para> + + There is, however, 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. + This User's Guide will introduce you step-by-step + to the relatively small amount of Python you'll + need to know to be able to use &SCons; effectively. + And Python is very easy to learn. + + </para> + + <para> + + One aspect of using Python as the + scripting language is 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> + # Arrange to build the "hello" program. + Program('hello.c') # "hello.c" is the source file. + </programlisting> + + <para> + + You'll see throughout the remainder of this Guide + 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> + + </section> + + <section> + <title>&SCons; Functions Are Order-Independent</title> + + <para> + + One important way in which the &SConstruct; + file is not exactly like a normal Python script, + and is more like a &Makefile;, + is that the order in which + the &SCons; functions are called in + the &SConstruct; file + does <emphasis>not</emphasis> + affect the order in which &SCons; + actually builds the programs and object files + you want it to build.<footnote> + <para>In programming parlance, + the &SConstruct; file is + <emphasis>declarative</emphasis>, + meaning you tell &SCons; what you want done + and let it figure out the order in which to do it, + rather than strictly <emphasis>imperative</emphasis>, + where you specify explicitly the order in + which to do things. + </para> + </footnote> + In other words, when you call the &b-link-Program; builder + (or any other builder method), + you're not telling &SCons; to build + the program at the instant the builder method is called. + Instead, you're telling &SCons; to build the program + that you want, for example, + a program built from a file named &hello_c;, + and it's up to &SCons; to build that program + (and any other files) whenever it's necessary. + (We'll learn more about how + &SCons; decides when building or rebuilding a file + is necessary in <xref linkend="chap-depends"></xref>, below.) + + </para> + + <para> + + &SCons; reflects this distinction between + <emphasis>calling a builder method like</emphasis> &b-Program; + and <emphasis>actually building the program</emphasis> + by printing the status messages that indicate + when it's "just reading" the &SConstruct; file, + and when it's actually building the target files. + This is to make it clear when &SCons; is + executing the Python statements that make up the &SConstruct; file, + and when &SCons; is actually executing the + commands or other actions to + build the necessary files. + + </para> + + <para> + + Let's clarify this with an example. + Python has a <literal>print</literal> statement that + prints a string of characters to the screen. + If we put <literal>print</literal> statements around + our calls to the &b-Program; builder method: + + </para> + + <programlisting> + print "Calling Program('hello.c')" + Program('hello.c') + print "Calling Program('goodbye.c')" + Program('goodbye.c') + print "Finished calling Program()" + </programlisting> + + <para> + + Then when we execute &SCons;, + we see the output from the <literal>print</literal> + statements in between the messages about + reading the &SConscript; files, + indicating that that is when the + Python statements are being executed: + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + Calling Program('hello.c') + Calling Program('goodbye.c') + Finished calling Program() + scons: done reading SConscript files. + scons: Building targets ... + cc -o goodbye.o -c goodbye.c + cc -o goodbye goodbye.o + cc -o hello.o -c hello.c + cc -o hello hello.o + scons: done building targets. + </screen> + + <para> + + Notice also that &SCons; built the &goodbye; program first, + even though the "reading &SConscript;" output + shows that we called <literal>Program('hello.c')</literal> + first in the &SConstruct; file. + + </para> + + </section> + + </section> + + <section> + <title>Making the &SCons; Output Less Verbose</title> + + <para> + + You've already seen how &SCons; prints + some messages about what it's doing, + surrounding the actual commands used to build the software: + + </para> + + <screen> + C:\><userinput>scons</userinput> + scons: Reading SConscript files ... + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + scons: done reading SConscript files. + scons: Building targets ... + cl /Fohello.obj /c hello.c /nologo + link /nologo /OUT:hello.exe hello.obj + scons: done building targets. + </screen> + + <para> + + These messages emphasize the + order in which &SCons; does its work: + all of the configuration files + (generically referred to as &SConscript; files) + are read and executed first, + and only then are the target files built. + Among other benefits, these messages help to distinguish between + errors that occur while the configuration files are read, + and errors that occur while targets are being built. + + </para> + + <para> + + One drawback, of course, is that these messages clutter the output. + Fortunately, they're easily disabled by using + the &Q; option when invoking &SCons;: + + </para> + + <screen> + C:\><userinput>scons -Q</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + cl /Fohello.obj /c hello.c /nologo + link /nologo /OUT:hello.exe hello.obj + </screen> + + <para> + + Because we want this User's Guide to focus + on what &SCons; is actually doing, + we're going to use the &Q; option + to remove these messages from the + output of all the remaining examples in this Guide. + + </para> + + </section> diff --git a/doc/user/sourcecode.in b/doc/user/sourcecode.in new file mode 100644 index 0000000..5cbbe1a --- /dev/null +++ b/doc/user/sourcecode.in @@ -0,0 +1,162 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + XXX + + </para> + + <section> + <title>Fetching Source Code From BitKeeper</title> + + <para> + + XXX + + </para> + + <scons_example name="ex_bitkeeper"> + <file name="SConstruct" printme="1"> + env = Environment() + env.SourceCode('.', env.BitKeeper()) + env.Program('hello.c') + </file> + <file name="s.hello.c"> + s.hello.c + </file> + </scons_example> + + <scons_output example="ex_bitkeeper"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Fetching Source Code From CVS</title> + + <para> + + XXX + + </para> + + <scons_example name="ex_cvs"> + <file name="SConstruct" printme="1"> + env = Environment() + env.SourceCode('.', env.CVS('/usr/local/CVS')) + env.Program('hello.c') + </file> + </scons_example> + + <scons_output example="ex_cvs"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Fetching Source Code From RCS</title> + + <para> + + XXX + + </para> + + <scons_example name="ex_rcs"> + <file name="SConstruct" printme="1"> + env = Environment() + env.SourceCode('.', env.RCS()) + env.Program('hello.c') + </file> + <file name="hello.c,v"> + hello.c,v + </file> + </scons_example> + + <scons_output example="ex_rcs"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Fetching Source Code From SCCS</title> + + <para> + + XXX + + </para> + + <scons_example name="ex_sccs"> + <file name="SConstruct" printme="1"> + env = Environment() + env.SourceCode('.', env.SCCS()) + env.Program('hello.c') + </file> + <file name="s.hello.c"> + s.hello.c + </file> + </scons_example> + + <scons_output example="ex_sccs"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <!-- + + <section> + <title>Fetching Source Code From Subversion</title> + + <para> + + XXX + + </para> + + <scons_example name="ex_subversion"> + <file name="SConstruct" printme="1"> + env = Environment() + env.SourceCode('.', env.Subversion('XXX')) + env.Program('hello.c') + </file> + </scons_example> + + <scons_output example="ex_subversion"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + --> diff --git a/doc/user/sourcecode.xml b/doc/user/sourcecode.xml new file mode 100644 index 0000000..aebcd20 --- /dev/null +++ b/doc/user/sourcecode.xml @@ -0,0 +1,157 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + XXX + + </para> + + <section> + <title>Fetching Source Code From BitKeeper</title> + + <para> + + XXX + + </para> + + <programlisting> + env = Environment() + env.SourceCode('.', env.BitKeeper()) + env.Program('hello.c') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + bk get hello.c + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + </section> + + <section> + <title>Fetching Source Code From CVS</title> + + <para> + + XXX + + </para> + + <programlisting> + env = Environment() + env.SourceCode('.', env.CVS('/usr/local/CVS')) + env.Program('hello.c') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + cvs -d /usr/local/CVS co hello.c + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + </section> + + <section> + <title>Fetching Source Code From RCS</title> + + <para> + + XXX + + </para> + + <programlisting> + env = Environment() + env.SourceCode('.', env.RCS()) + env.Program('hello.c') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + co hello.c + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + </section> + + <section> + <title>Fetching Source Code From SCCS</title> + + <para> + + XXX + + </para> + + <programlisting> + env = Environment() + env.SourceCode('.', env.SCCS()) + env.Program('hello.c') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + sccs get hello.c + cc -o hello.o -c hello.c + cc -o hello hello.o + </screen> + + </section> + + <!-- + + <section> + <title>Fetching Source Code From Subversion</title> + + <para> + + XXX + + </para> + + <scons_example name="ex_subversion"> + <file name="SConstruct" printme="1"> + env = Environment() + env.SourceCode('.', env.Subversion('XXX')) + env.Program('hello.c') + </file> + </scons_example> + + <scons_output example="ex_subversion"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + --> diff --git a/doc/user/tasks.in b/doc/user/tasks.in new file mode 100644 index 0000000..14775c8 --- /dev/null +++ b/doc/user/tasks.in @@ -0,0 +1,108 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> +There is a common set of simple tasks that many build configurations rely +on as they become more complex. Most build tools have special +purpose constructs for performing these tasks, but since &SConscript; +files are &Python; scripts, you can use more flexible built-in &Python; +services to perform these tasks. This appendix lists a number of these +tasks and how to implement them in &Python;. +</para> + +<example> +<title>Wildcard globbing to create a list of filenames</title> +<programlisting> +files = Glob(wildcard) +</programlisting> +</example> + +<example> +<title>Filename extension substitution</title> +<programlisting> +import os.path +filename = os.path.splitext(filename)[0]+extension +</programlisting> +</example> + +<example> +<title>Appending a path prefix to a list of filenames</title> +<programlisting> +import os.path +filenames = [os.path.join(prefix, x) for x in filenames] +</programlisting> + +<simpara>or in Python 1.5.2:</simpara> + +<programlisting> +import os.path +new_filenames = [] +for x in filenames: + new_filenames.append(os.path.join(prefix, x)) +</programlisting> +</example> + +<example> +<title>Substituting a path prefix with another one</title> +<programlisting> +if filename.find(old_prefix) == 0: + filename = filename.replace(old_prefix, new_prefix) +</programlisting> + +<simpara>or in Python 1.5.2:</simpara> + +<programlisting> +import string +if string.find(filename, old_prefix) == 0: + filename = string.replace(filename, old_prefix, new_prefix) +</programlisting> +</example> + +<example> +<title>Filtering a filename list to exclude/retain only a specific set +of extensions</title> +<programlisting> +import os.path +filenames = [x for x in filenames if os.path.splitext(x)[1] in extensions] +</programlisting> + +<simpara>or in Python 1.5.2:</simpara> + +<programlisting> +import os.path +new_filenames = [] +for x in filenames: + if os.path.splitext(x)[1] in extensions: + new_filenames.append(x) +</programlisting> +</example> + +<example> +<title>The "backtick function": run a shell command and capture the +output</title> +<programlisting>import os +output = os.popen(command).read() +</programlisting> +</example> diff --git a/doc/user/tasks.xml b/doc/user/tasks.xml new file mode 100644 index 0000000..14775c8 --- /dev/null +++ b/doc/user/tasks.xml @@ -0,0 +1,108 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> +There is a common set of simple tasks that many build configurations rely +on as they become more complex. Most build tools have special +purpose constructs for performing these tasks, but since &SConscript; +files are &Python; scripts, you can use more flexible built-in &Python; +services to perform these tasks. This appendix lists a number of these +tasks and how to implement them in &Python;. +</para> + +<example> +<title>Wildcard globbing to create a list of filenames</title> +<programlisting> +files = Glob(wildcard) +</programlisting> +</example> + +<example> +<title>Filename extension substitution</title> +<programlisting> +import os.path +filename = os.path.splitext(filename)[0]+extension +</programlisting> +</example> + +<example> +<title>Appending a path prefix to a list of filenames</title> +<programlisting> +import os.path +filenames = [os.path.join(prefix, x) for x in filenames] +</programlisting> + +<simpara>or in Python 1.5.2:</simpara> + +<programlisting> +import os.path +new_filenames = [] +for x in filenames: + new_filenames.append(os.path.join(prefix, x)) +</programlisting> +</example> + +<example> +<title>Substituting a path prefix with another one</title> +<programlisting> +if filename.find(old_prefix) == 0: + filename = filename.replace(old_prefix, new_prefix) +</programlisting> + +<simpara>or in Python 1.5.2:</simpara> + +<programlisting> +import string +if string.find(filename, old_prefix) == 0: + filename = string.replace(filename, old_prefix, new_prefix) +</programlisting> +</example> + +<example> +<title>Filtering a filename list to exclude/retain only a specific set +of extensions</title> +<programlisting> +import os.path +filenames = [x for x in filenames if os.path.splitext(x)[1] in extensions] +</programlisting> + +<simpara>or in Python 1.5.2:</simpara> + +<programlisting> +import os.path +new_filenames = [] +for x in filenames: + if os.path.splitext(x)[1] in extensions: + new_filenames.append(x) +</programlisting> +</example> + +<example> +<title>The "backtick function": run a shell command and capture the +output</title> +<programlisting>import os +output = os.popen(command).read() +</programlisting> +</example> diff --git a/doc/user/tools.in b/doc/user/tools.in new file mode 100644 index 0000000..cc0628e --- /dev/null +++ b/doc/user/tools.in @@ -0,0 +1,38 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + +This appendix contains descriptions of all of the +Tools modules that are +available "out of the box" in this version of SCons. + +</para> + +<variablelist> + +&tools-gen; + +</variablelist> diff --git a/doc/user/tools.xml b/doc/user/tools.xml new file mode 100644 index 0000000..cc0628e --- /dev/null +++ b/doc/user/tools.xml @@ -0,0 +1,38 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + +This appendix contains descriptions of all of the +Tools modules that are +available "out of the box" in this version of SCons. + +</para> + +<variablelist> + +&tools-gen; + +</variablelist> diff --git a/doc/user/troubleshoot.in b/doc/user/troubleshoot.in new file mode 100644 index 0000000..c729149 --- /dev/null +++ b/doc/user/troubleshoot.in @@ -0,0 +1,875 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + The experience of configuring any + software build tool to build a large code base + usually, at some point, + involves trying to figure out why + the tool is behaving a certain way, + and how to get it to behave the way you want. + &SCons; is no different. + This appendix contains a number of + different ways in which you can + get some additional insight into &SCons' behavior. + + </para> + + <para> + + Note that we're always interested in trying to + improve how you can troubleshoot configuration problems. + If you run into a problem that has + you scratching your head, + and which there just doesn't seem to be a good way to debug, + odds are pretty good that someone else will run into + the same problem, too. + If so, please let the SCons development team know + (preferably by filing a bug report + or feature request at our project pages at tigris.org) + so that we can use your feedback + to try to come up with a better way to help you, + and others, get the necessary insight into &SCons; behavior + to help identify and fix configuration issues. + + </para> + + <section> + <title>Why is That Target Being Rebuilt? the &debug-explain; Option</title> + + <para> + + Let's look at a simple example of + a misconfigured build + that causes a target to be rebuilt + every time &SCons; is run: + + </para> + + <scons_example name="explain1"> + <file name="SConstruct" printme="1"> + # Intentionally misspell the output file name in the + # command used to create the file: + Command('file.out', 'file.in', 'cp $SOURCE file.oout') + </file> + <file name="file.in"> + file.in + </file> + </scons_example> + + <para> + + (Note to Windows users: The POSIX &cp; command + copies the first file named on the command line + to the second file. + In our example, it copies the &file_in; file + to the &file_out; file.) + + </para> + + <para> + + Now if we run &SCons; multiple times on this example, + we see that it re-runs the &cp; + command every time: + + </para> + + <scons_output example="explain1" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + In this example, + the underlying cause is obvious: + we've intentionally misspelled the output file name + in the &cp; command, + so the command doesn't actually + build the &file_out; file that we've told &SCons; to expect. + But if the problem weren't obvious, + it would be helpful + to specify the &debug-explain; option + on the command line + to have &SCons; tell us very specifically + why it's decided to rebuild the target: + + </para> + + <scons_output example="explain1" os="posix"> + <scons_output_command>scons -Q --debug=explain</scons_output_command> + </scons_output> + + <para> + + If this had been a more complicated example + involving a lot of build output, + having &SCons; tell us that + it's trying to rebuild the target file + because it doesn't exist + would be an important clue + that something was wrong with + the command that we invoked to build it. + + </para> + + <para> + + The &debug-explain; option also comes in handy + to help figure out what input file changed. + Given a simple configuration that builds + a program from three source files, + changing one of the source files + and rebuilding with the &debug-explain; + option shows very specifically + why &SCons; rebuilds the files that it does: + + </para> + + <scons_example name="explain2"> + <file name="SConstruct"> + Program('prog', ['file1.c', 'file2.c', 'file3.c']) + </file> + <file name="file1.c"> + file1.c + </file> + <file name="file2.c"> + file2.c + </file> + <file name="file3.c"> + file3.c + </file> + </scons_example> + + <scons_output example="explain2" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command output=" [CHANGE THE CONTENTS OF file2.c]">edit file2.c</scons_output_command> + <scons_output_command>scons -Q --debug=explain</scons_output_command> + </scons_output> + + <para> + + This becomes even more helpful + in identifying when a file is rebuilt + due to a change in an implicit dependency, + such as an incuded <filename>.h</filename> file. + If the <filename>file1.c</filename> + and <filename>file3.c</filename> files + in our example + both included a &hello_h; file, + then changing that included file + and re-running &SCons; with the &debug-explain; option + will pinpoint that it's the change to the included file + that starts the chain of rebuilds: + + </para> + + <scons_example name="explain3"> + <file name="SConstruct"> + Program('prog', ['file1.c', 'file2.c', 'file3.c'], CPPPATH='.') + </file> + <file name="file1.c"> + #include <hello.h> + file1.c + </file> + <file name="file2.c"> + file2.c + </file> + <file name="file3.c"> + #include <hello.h> + file3.c + </file> + <file name="hello.h"> + #define string "world" + </file> + </scons_example> + + <scons_output example="explain3" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command output=" [CHANGE THE CONTENTS OF hello.h]">edit hello.h</scons_output_command> + <scons_output_command>scons -Q --debug=explain</scons_output_command> + </scons_output> + + <para> + + (Note that the &debug-explain; option will only tell you + why &SCons; decided to rebuild necessary targets. + It does not tell you what files it examined + when deciding <emphasis>not</emphasis> + to rebuild a target file, + which is often a more valuable question to answer.) + + </para> + + </section> + + <section> + <title>What's in That Construction Environment? the &Dump; Method</title> + + <para> + + When you create a construction environment, + &SCons; populates it + with construction variables that are set up + for various compilers, linkers and utilities + that it finds on your system. + Although this is usually helpful and what you want, + it might be frustrating if &SCons; + doesn't set certain variables that you + expect to be set. + In situations like this, + it's sometimes helpful to use the + construction environment &Dump; method + to print all or some of + the construction variables. + Note that the &Dump; method + <emphasis>returns</emphasis> + the representation of the variables + in the environment + for you to print (or otherwise manipulate): + + </para> + + <scons_example name="Dump"> + <file name="SConstruct" printme="1"> + env = Environment() + print env.Dump() + </file> + </scons_example> + + <para> + + On a POSIX system with gcc installed, + this might generate: + + </para> + + <scons_output example="Dump" os="posix" tools="gcc"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + On a Windows system with Visual C++ + the output might look like: + + </para> + + <scons_output example="Dump" os="win32" tools="msvc"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + The construction environments in these examples have + actually been restricted to just gcc and Visual C++, + respectively. + In a real-life situation, + the construction environments will + likely contain a great many more variables. + Also note that we've massaged the example output above + to make the memory address of all objects a constant 0x700000. + In reality, you would see a different hexadecimal + number for each object. + + </para> + + <para> + + To make it easier to see just what you're + interested in, + the &Dump; method allows you to + specify a specific constrcution variable + that you want to disply. + For example, + it's not unusual to want to verify + the external environment used to execute build commands, + to make sure that the PATH and other + environment variables are set up the way they should be. + You can do this as follows: + + </para> + + <scons_example name="Dump_ENV"> + <file name="SConstruct" printme="1"> + env = Environment() + print env.Dump('ENV') + </file> + </scons_example> + + <para> + + Which might display the following when executed on a POSIX system: + + </para> + + <scons_output example="Dump_ENV" os="posix"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + And the following when executed on a Windows system: + + </para> + + <scons_output example="Dump_ENV" os="win32"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + </section> + + <section> + + <title>What Dependencies Does &SCons; Know About? the &tree; Option</title> + + <para> + + Sometimes the best way to try to figure out what + &SCons; is doing is simply to take a look at the + dependency graph that it constructs + based on your &SConscript; files. + The <literal>--tree</literal> option + will display all or part of the + &SCons; dependency graph in an + "ASCII art" graphical format + that shows the dependency hierarchy. + + </para> + + <para> + + For example, given the following input &SConstruct; file: + + </para> + + <scons_example name="tree1"> + <file name="SConstruct" printme="1"> + env = Environment(CPPPATH = ['.']) + env.Program('prog', ['f1.c', 'f2.c', 'f3.c']) + </file> + <file name="f1.c"> + #include "inc.h" + </file> + <file name="f2.c"> + #include "inc.h" + </file> + <file name="f3.c"> + #include "inc.h" + </file> + <file name="inc.h"> + inc.h + </file> + </scons_example> + + <para> + + Running &SCons; with the <literal>--tree=all</literal> + option yields: + + </para> + + <scons_output example="tree1"> + <scons_output_command>scons -Q --tree=all</scons_output_command> + </scons_output> + + <para> + + The tree will also be printed when the + <literal>-n</literal> (no execute) option is used, + which allows you to examine the dependency graph + for a configuration without actually + rebuilding anything in the tree. + + </para> + + <para> + + The <literaL>--tree</literal> option only prints + the dependency graph for the specified targets + (or the default target(s) if none are specified on the command line). + So if you specify a target like <filename>f2.o</filename> + on the command line, + the <literaL>--tree</literal> option will only + print the dependency graph for that file: + + </para> + + <scons_output example="tree1"> + <scons_output_command>scons -Q --tree=all f2.o</scons_output_command> + </scons_output> + + <para> + + This is, of course, useful for + restricting the output from a very large + build configuration to just a + portion in which you're interested. + Multiple targets are fine, + in which case a tree will be printed + for each specified target: + + </para> + + <scons_output example="tree1"> + <scons_output_command>scons -Q --tree=all f1.o f3.o</scons_output_command> + </scons_output> + + <para> + + The <literal>status</literal> argument may be used + to tell &SCons; to print status information about + each file in the dependency graph: + + </para> + + <scons_output example="tree1"> + <scons_output_command>scons -Q --tree=status</scons_output_command> + </scons_output> + + <para> + + Note that <literal>--tree=all,status</literal> is equivalent; + the <literal>all</literal> + is assumed if only <literal>status</literal> is present. + As an alternative to <literal>all</literal>, + you can specify <literal>--tree=derived</literal> + to have &SCons; only print derived targets + in the tree output, + skipping source files + (like <filename>.c</filename> and <filename>.h</filename> files): + + </para> + + <scons_output example="tree1"> + <scons_output_command>scons -Q --tree=derived</scons_output_command> + </scons_output> + + <para> + + You can use the <literal>status</literal> + modifier with <literal>derived</literal> as well: + + </para> + + <scons_output example="tree1"> + <scons_output_command>scons -Q --tree=derived,status</scons_output_command> + </scons_output> + + <para> + + Note that the order of the <literal>--tree=</literal> + arguments doesn't matter; + <literal>--tree=status,derived</literal> is + completely equivalent. + + </para> + + <para> + + The default behavior of the <literal>--tree</literal> option + is to repeat all of the dependencies each time the library dependency + (or any other dependency file) is encountered in the tree. + If certain target files share other target files, + such as two programs that use the same library: + + </para> + + <scons_example name="tree2"> + <file name="SConstruct" printme="1"> + env = Environment(CPPPATH = ['.'], + LIBS = ['foo'], + LIBPATH = ['.']) + env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) + env.Program('prog1.c') + env.Program('prog2.c') + </file> + <file name="prog1.c"> + #include "inc.h" + </file> + <file name="prog2.c"> + #include "inc.h" + </file> + <file name="f1.c"> + #include "inc.h" + </file> + <file name="f2.c"> + #include "inc.h" + </file> + <file name="f3.c"> + #include "inc.h" + </file> + <file name="inc.h"> + inc.h + </file> + </scons_example> + + <para> + + Then there can be a <emphasis>lot</emphasis> of repetition in the + <literal>--tree=</literal> output: + + </para> + + <scons_output example="tree2"> + <scons_output_command>scons -Q --tree=all</scons_output_command> + </scons_output> + + <para> + + In a large configuration with many internal libraries + and include files, + this can very quickly lead to huge output trees. + To help make this more manageable, + a <literal>prune</literal> modifier may + be added to the option list, + in which case &SCons; + will print the name of a target that has + already been visited during the tree-printing + in <literal>[square brackets]</literal> + as an indication that the dependencies + of the target file may be found + by looking farther up the tree: + + </para> + + <scons_output example="tree2"> + <scons_output_command>scons -Q --tree=prune</scons_output_command> + </scons_output> + + <para> + + Like the <literal>status</literal> keyword, + the <literal>prune</literal> argument by itself + is equivalent to <literal>--tree=all,prune</literal>. + + </para> + + </section> + + <section> + + <title>How is &SCons; Constructing the Command Lines It Executes? the &debug-presub; Option</title> + + <para> + + Sometimes it's useful to look at the + pre-substitution string + that &SCons; uses to generate + the command lines it executes. + This can be done with the &debug-presub; option: + + </para> + + <scons_example name="presub"> + <file name="SConstruct"> + env = Environment(CPPPATH = ['.']) + env.Program('prog', 'prog.c') + </file> + <file name="prog.c"> + prog.c + </file> + </scons_example> + + <!-- + + Have to capture output here, otherwise the - -debug=presub output + shows the Python functions from the sconsdoc.py execution wrapper + used to generate this manual, not the underlying command-line strings. + + <scons_output example="presub"> + <scons_output_command>scons -Q - -debug=presub</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q --debug=presub</userinput> + Building prog.o with action: + $CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCOMCOM $SOURCES + cc -o prog.o -c -I. prog.c + Building prog with action: + $SMART_LINKCOM + cc -o prog prog.o + </screen> + + </section> + + <section> + + <title>Where is &SCons; Searching for Libraries? the &debug-findlibs; Option</title> + + <para> + + To get some insight into what library names + &SCons; is searching for, + and in which directories it is searching, + Use the <literal>--debug=findlibs</literal> option. + Given the following input &SConstruct; file: + + </para> + + <scons_example name="findlibs"> + <file name="SConstruct" printme="1"> + env = Environment(LIBPATH = ['libs1', 'libs2']) + env.Program('prog.c', LIBS=['foo', 'bar']) + </file> + <file name="prog.c"> + prog.c + </file> + <file name="libs1/libfoo.a"> + libs1/libfoo.a + </file> + <file name="libs2/libbar.a"> + libs2/libbar.a + </file> + </scons_example> + + <para> + + And the libraries <filename>libfoo.a</filename> + and <filename>libbar.a</filename> + in <filename>libs1</filename> and <filename>libs2</filename>, + respectively, + use of the <literal>--debug=findlibs</literal> option yields: + + </para> + + <scons_output example="findlibs"> + <scons_output_command>scons -Q --debug=findlibs</scons_output_command> + </scons_output> + + </section> + + <!-- + + <section> + + <title>What Implicit Dependencies Did the &SCons; Scanner find? the &debug-includes; Option</title> + + <para> + + XXX explain the - - debug=includes option + + </para> + + <scons_example name="includes"> + <file name="SConstruct" printme="1"> + env = Environment(CPPPATH = ['inc1', 'inc2']) + env.Program('prog.c') + </file> + <file name="prog.c"> + #include "file1.h" + #include "file2.h" + prog.c + </file> + <file name="inc1/file1.h"> + inc1/file1.h + </file> + <file name="inc2/file2.h"> + inc2/file2.h + </file> + </scons_example> + + <scons_output example="includes"> + <scons_output_command>scons -Q - - debug=includes prog</scons_output_command> + </scons_output> + + </section> + + --> + + <section> + + <title>Where is &SCons; Blowing Up? the &debug-stacktrace; Option</title> + + <para> + + In general, &SCons; tries to keep its error + messages short and informative. + That means we usually try to avoid showing + the stack traces that are familiar + to experienced Python programmers, + since they usually contain much more + information than is useful to most people. + + </para> + + <para> + + For example, the following &SConstruct file: + + </para> + + <scons_example name="stacktrace"> + <file name="SConstruct" printme="1"> + Program('prog.c') + </file> + </scons_example> + + <para> + + Generates the following error if the + <filename>prog.c</filename> file + does not exist: + + </para> + + <scons_output example="stacktrace"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + In this case, + the error is pretty obvious. + But if it weren't, + and you wanted to try to get more information + about the error, + the &debug-stacktrace; option + would show you exactly where in the &SCons; source code + the problem occurs: + + </para> + + <scons_output example="stacktrace"> + <scons_output_command>scons -Q --debug=stacktrace</scons_output_command> + </scons_output> + + <para> + + Of course, if you do need to dive into the &SCons; source code, + we'd like to know if, or how, + the error messages or troubleshooting options + could have been improved to avoid that. + Not everyone has the necessary time or + Python skill to dive into the source code, + and we'd like to improve &SCons; + for those people as well... + + </para> + + </section> + + <section> + + <title>How is &SCons; Making Its Decisions? the &taskmastertrace; Option</title> + + <para> + + The internal &SCons; subsystem that handles walking + the dependency graph + and controls the decision-making about what to rebuild + is the <literal>Taskmaster</literal>. + &SCons; supports a <literal>--taskmastertrace</literal> + option that tells the Taskmaster to print + information about the children (dependencies) + of the various Nodes on its walk down the graph, + which specific dependent Nodes are being evaluated, + and in what order. + + </para> + + <para> + + The <literal>--taskmastertrace</literal> option + takes as an argument the name of a file in + which to put the trace output, + with <filename>-</filename> (a single hyphen) + indicating that the trace messages + should be printed to the standard output: + + </para> + + <scons_example name="taskmastertrace"> + <file name="SConstruct" printme="1"> + env = Environment(CPPPATH = ['.']) + env.Program('prog.c') + </file> + <file name="prog.c"> + #include "inc.h" + prog.c + </file> + <file name="inc.h"> + #define STRING "one" + </file> + </scons_example> + + <scons_output example="taskmastertrace" os="posix"> + <scons_output_command>scons -Q --taskmastertrace=- prog</scons_output_command> + </scons_output> + + <para> + + The <literal>--taskmastertrace</literal> option + doesn't provide information about the actual + calculations involved in deciding if a file is up-to-date, + but it does show all of the dependencies + it knows about for each Node, + and the order in which those dependencies are evaluated. + This can be useful as an alternate way to determine + whether or not your &SCons; configuration, + or the implicit dependency scan, + has actually identified all the correct dependencies + you want it to. + + </para> + + </section> + + <!-- + + <section> + + <title>Where Are My Build Bottlenecks? the &profile; Option</title> + + <para> + + XXX explain the - - profile= option + + </para> + + </section> + + --> + + <!-- + + <section> + <title>Troubleshooting Shared Caching: the &cache-debug; Option</title> + + <para> + + XXX describe the - - cache-debug option + XXX maybe point to the caching.in chapter? + + </para> + + </section> + + --> diff --git a/doc/user/troubleshoot.xml b/doc/user/troubleshoot.xml new file mode 100644 index 0000000..6bd53f9 --- /dev/null +++ b/doc/user/troubleshoot.xml @@ -0,0 +1,1313 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + + The experience of configuring any + software build tool to build a large code base + usually, at some point, + involves trying to figure out why + the tool is behaving a certain way, + and how to get it to behave the way you want. + &SCons; is no different. + This appendix contains a number of + different ways in which you can + get some additional insight into &SCons;' behavior. + + </para> + + <para> + + Note that we're always interested in trying to + improve how you can troubleshoot configuration problems. + If you run into a problem that has + you scratching your head, + and which there just doesn't seem to be a good way to debug, + odds are pretty good that someone else will run into + the same problem, too. + If so, please let the SCons development team know + (preferably by filing a bug report + or feature request at our project pages at tigris.org) + so that we can use your feedback + to try to come up with a better way to help you, + and others, get the necessary insight into &SCons; behavior + to help identify and fix configuration issues. + + </para> + + <section> + <title>Why is That Target Being Rebuilt? the &debug-explain; Option</title> + + <para> + + Let's look at a simple example of + a misconfigured build + that causes a target to be rebuilt + every time &SCons; is run: + + </para> + + <programlisting> + # Intentionally misspell the output file name in the + # command used to create the file: + Command('file.out', 'file.in', 'cp $SOURCE file.oout') + </programlisting> + + <para> + + (Note to Windows users: The POSIX &cp; command + copies the first file named on the command line + to the second file. + In our example, it copies the &file_in; file + to the &file_out; file.) + + </para> + + <para> + + Now if we run &SCons; multiple times on this example, + we see that it re-runs the &cp; + command every time: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cp file.in file.oout + % <userinput>scons -Q</userinput> + cp file.in file.oout + % <userinput>scons -Q</userinput> + cp file.in file.oout + </screen> + + <para> + + In this example, + the underlying cause is obvious: + we've intentionally misspelled the output file name + in the &cp; command, + so the command doesn't actually + build the &file_out; file that we've told &SCons; to expect. + But if the problem weren't obvious, + it would be helpful + to specify the &debug-explain; option + on the command line + to have &SCons; tell us very specifically + why it's decided to rebuild the target: + + </para> + + <screen> + % <userinput>scons -Q --debug=explain</userinput> + scons: building `file.out' because it doesn't exist + cp file.in file.oout + </screen> + + <para> + + If this had been a more complicated example + involving a lot of build output, + having &SCons; tell us that + it's trying to rebuild the target file + because it doesn't exist + would be an important clue + that something was wrong with + the command that we invoked to build it. + + </para> + + <para> + + The &debug-explain; option also comes in handy + to help figure out what input file changed. + Given a simple configuration that builds + a program from three source files, + changing one of the source files + and rebuilding with the &debug-explain; + option shows very specifically + why &SCons; rebuilds the files that it does: + + </para> + + + + <screen> + % <userinput>scons -Q</userinput> + cc -o file1.o -c file1.c + cc -o file2.o -c file2.c + cc -o file3.o -c file3.c + cc -o prog file1.o file2.o file3.o + % <userinput>edit file2.c</userinput> + [CHANGE THE CONTENTS OF file2.c] + % <userinput>scons -Q --debug=explain</userinput> + scons: rebuilding `file2.o' because `file2.c' changed + cc -o file2.o -c file2.c + scons: rebuilding `prog' because `file2.o' changed + cc -o prog file1.o file2.o file3.o + </screen> + + <para> + + This becomes even more helpful + in identifying when a file is rebuilt + due to a change in an implicit dependency, + such as an incuded <filename>.h</filename> file. + If the <filename>file1.c</filename> + and <filename>file3.c</filename> files + in our example + both included a &hello_h; file, + then changing that included file + and re-running &SCons; with the &debug-explain; option + will pinpoint that it's the change to the included file + that starts the chain of rebuilds: + + </para> + + + + <screen> + % <userinput>scons -Q</userinput> + cc -o file1.o -c -I. file1.c + cc -o file2.o -c -I. file2.c + cc -o file3.o -c -I. file3.c + cc -o prog file1.o file2.o file3.o + % <userinput>edit hello.h</userinput> + [CHANGE THE CONTENTS OF hello.h] + % <userinput>scons -Q --debug=explain</userinput> + scons: rebuilding `file1.o' because `hello.h' changed + cc -o file1.o -c -I. file1.c + scons: rebuilding `file3.o' because `hello.h' changed + cc -o file3.o -c -I. file3.c + scons: rebuilding `prog' because: + `file1.o' changed + `file3.o' changed + cc -o prog file1.o file2.o file3.o + </screen> + + <para> + + (Note that the &debug-explain; option will only tell you + why &SCons; decided to rebuild necessary targets. + It does not tell you what files it examined + when deciding <emphasis>not</emphasis> + to rebuild a target file, + which is often a more valuable question to answer.) + + </para> + + </section> + + <section> + <title>What's in That Construction Environment? the &Dump; Method</title> + + <para> + + When you create a construction environment, + &SCons; populates it + with construction variables that are set up + for various compilers, linkers and utilities + that it finds on your system. + Although this is usually helpful and what you want, + it might be frustrating if &SCons; + doesn't set certain variables that you + expect to be set. + In situations like this, + it's sometimes helpful to use the + construction environment &Dump; method + to print all or some of + the construction variables. + Note that the &Dump; method + <emphasis>returns</emphasis> + the representation of the variables + in the environment + for you to print (or otherwise manipulate): + + </para> + + <programlisting> + env = Environment() + print env.Dump() + </programlisting> + + <para> + + On a POSIX system with gcc installed, + this might generate: + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + { 'BUILDERS': {'_InternalInstall': <function InstallBuilderWrapper at 0x700000>, '_InternalInstallAs': <function InstallAsBuilderWrapper at 0x700000>}, + 'CONFIGUREDIR': '#/.sconf_temp', + 'CONFIGURELOG': '#/config.log', + 'CPPSUFFIXES': [ '.c', + '.C', + '.cxx', + '.cpp', + '.c++', + '.cc', + '.h', + '.H', + '.hxx', + '.hpp', + '.hh', + '.F', + '.fpp', + '.FPP', + '.m', + '.mm', + '.S', + '.spp', + '.SPP'], + 'DSUFFIXES': ['.d'], + 'Dir': <SCons.Defaults.Variable_Method_Caller instance at 0x700000>, + 'Dirs': <SCons.Defaults.Variable_Method_Caller instance at 0x700000>, + 'ENV': {'PATH': '/usr/local/bin:/opt/bin:/bin:/usr/bin'}, + 'ESCAPE': <function escape at 0x700000>, + 'File': <SCons.Defaults.Variable_Method_Caller instance at 0x700000>, + 'HOST_ARCH': None, + 'HOST_OS': None, + 'IDLSUFFIXES': ['.idl', '.IDL'], + 'INSTALL': <function copyFunc at 0x700000>, + 'LIBPREFIX': 'lib', + 'LIBPREFIXES': ['$LIBPREFIX'], + 'LIBSUFFIX': '.a', + 'LIBSUFFIXES': ['$LIBSUFFIX', '$SHLIBSUFFIX'], + 'MAXLINELENGTH': 128072, + 'OBJPREFIX': '', + 'OBJSUFFIX': '.o', + 'PLATFORM': 'posix', + 'PROGPREFIX': '', + 'PROGSUFFIX': '', + 'PSPAWN': <function piped_env_spawn at 0x700000>, + 'RDirs': <SCons.Defaults.Variable_Method_Caller instance at 0x700000>, + 'SCANNERS': [], + 'SHELL': 'sh', + 'SHLIBPREFIX': '$LIBPREFIX', + 'SHLIBSUFFIX': '.so', + 'SHOBJPREFIX': '$OBJPREFIX', + 'SHOBJSUFFIX': '$OBJSUFFIX', + 'SPAWN': <function spawnvpe_spawn at 0x700000>, + 'TARGET_ARCH': None, + 'TARGET_OS': None, + 'TEMPFILE': <class SCons.Platform.TempFileMunge at 0x700000>, + 'TEMPFILEPREFIX': '@', + 'TOOLS': ['install', 'install'], + '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}', + '_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', + '_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', + '_LIBFLAGS': '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}', + '__RPATH': '$_RPATH', + '_concat': <function _concat at 0x700000>, + '_defines': <function _defines at 0x700000>, + '_stripixes': <function _stripixes at 0x700000>} + scons: done reading SConscript files. + scons: Building targets ... + scons: `.' is up to date. + scons: done building targets. + </screen> + + <para> + + On a Windows system with Visual C++ + the output might look like: + + </para> + + <screen> + C:\><userinput>scons</userinput> + scons: Reading SConscript files ... + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + { 'BUILDERS': {'_InternalInstall': <function InstallBuilderWrapper at 0x700000>, 'Object': <SCons.Builder.CompositeBuilder instance at 0x700000>, 'PCH': <SCons.Builder.BuilderBase instance at 0x700000>, 'RES': <SCons.Builder.BuilderBase instance at 0x700000>, 'SharedObject': <SCons.Builder.CompositeBuilder instance at 0x700000>, 'StaticObject': <SCons.Builder.CompositeBuilder instance at 0x700000>, '_InternalInstallAs': <function InstallAsBuilderWrapper at 0x700000>}, + 'CC': 'cl', + 'CCCOM': <SCons.Action.FunctionAction instance at 0x700000>, + 'CCFLAGS': ['/nologo'], + 'CCPCHFLAGS': ['${(PCH and "/Yu%s /Fp%s"%(PCHSTOP or "",File(PCH))) or ""}'], + 'CCPDBFLAGS': ['${(PDB and "/Z7") or ""}'], + 'CFILESUFFIX': '.c', + 'CFLAGS': [], + 'CONFIGUREDIR': '#/.sconf_temp', + 'CONFIGURELOG': '#/config.log', + 'CPPDEFPREFIX': '/D', + 'CPPDEFSUFFIX': '', + 'CPPSUFFIXES': [ '.c', + '.C', + '.cxx', + '.cpp', + '.c++', + '.cc', + '.h', + '.H', + '.hxx', + '.hpp', + '.hh', + '.F', + '.fpp', + '.FPP', + '.m', + '.mm', + '.S', + '.spp', + '.SPP'], + 'CXX': '$CC', + 'CXXCOM': '$CXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $CXXFLAGS $CCFLAGS $_CCCOMCOM', + 'CXXFILESUFFIX': '.cc', + 'CXXFLAGS': ['$(', '/TP', '$)'], + 'DSUFFIXES': ['.d'], + 'Dir': <SCons.Defaults.Variable_Method_Caller instance at 0x700000>, + 'Dirs': <SCons.Defaults.Variable_Method_Caller instance at 0x700000>, + 'ENV': { 'PATH': 'C:/WINDOWS\\System32', + 'PATHEXT': '.COM;.EXE;.BAT;.CMD', + 'SystemRoot': 'C:/WINDOWS'}, + 'ESCAPE': <function escape at 0x700000>, + 'File': <SCons.Defaults.Variable_Method_Caller instance at 0x700000>, + 'HOST_ARCH': '', + 'HOST_OS': 'win32', + 'IDLSUFFIXES': ['.idl', '.IDL'], + 'INCPREFIX': '/I', + 'INCSUFFIX': '', + 'INSTALL': <function copyFunc at 0x700000>, + 'LIBPREFIX': '', + 'LIBPREFIXES': ['$LIBPREFIX'], + 'LIBSUFFIX': '.lib', + 'LIBSUFFIXES': ['$LIBSUFFIX'], + 'MAXLINELENGTH': 2048, + 'MSVC_SETUP_RUN': True, + 'OBJPREFIX': '', + 'OBJSUFFIX': '.obj', + 'PCHCOM': '$CXX /Fo${TARGETS[1]} $CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS $PCHPDBFLAGS', + 'PCHPDBFLAGS': ['${(PDB and "/Yd") or ""}'], + 'PLATFORM': 'win32', + 'PROGPREFIX': '', + 'PROGSUFFIX': '.exe', + 'PSPAWN': <function piped_spawn at 0x700000>, + 'RC': 'rc', + 'RCCOM': <SCons.Action.FunctionAction instance at 0x700000>, + 'RCFLAGS': [], + 'RCSUFFIXES': ['.rc', '.rc2'], + 'RDirs': <SCons.Defaults.Variable_Method_Caller instance at 0x700000>, + 'SCANNERS': [], + 'SHCC': '$CC', + 'SHCCCOM': <SCons.Action.FunctionAction instance at 0x700000>, + 'SHCCFLAGS': ['$CCFLAGS'], + 'SHCFLAGS': ['$CFLAGS'], + 'SHCXX': '$CXX', + 'SHCXXCOM': '$SHCXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $SHCXXFLAGS $SHCCFLAGS $_CCCOMCOM', + 'SHCXXFLAGS': ['$CXXFLAGS'], + 'SHELL': None, + 'SHLIBPREFIX': '', + 'SHLIBSUFFIX': '.dll', + 'SHOBJPREFIX': '$OBJPREFIX', + 'SHOBJSUFFIX': '$OBJSUFFIX', + 'SPAWN': <function spawn at 0x700000>, + 'STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME': 1, + 'TARGET_ARCH': '', + 'TARGET_OS': 'win32', + 'TEMPFILE': <class SCons.Platform.TempFileMunge at 0x700000>, + 'TEMPFILEPREFIX': '@', + 'TOOLS': ['msvc', 'install', 'install'], + '_CCCOMCOM': '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $CCPCHFLAGS $CCPDBFLAGS', + '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}', + '_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', + '_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', + '_LIBFLAGS': '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}', + '_MSVC_OUTPUT_FLAG': <function msvc_output_flag at 0x700000>, + '_concat': <function _concat at 0x700000>, + '_defines': <function _defines at 0x700000>, + '_stripixes': <function _stripixes at 0x700000>} + scons: done reading SConscript files. + scons: Building targets ... + scons: `.' is up to date. + scons: done building targets. + </screen> + + <para> + + The construction environments in these examples have + actually been restricted to just gcc and Visual C++, + respectively. + In a real-life situation, + the construction environments will + likely contain a great many more variables. + Also note that we've massaged the example output above + to make the memory address of all objects a constant 0x700000. + In reality, you would see a different hexadecimal + number for each object. + + </para> + + <para> + + To make it easier to see just what you're + interested in, + the &Dump; method allows you to + specify a specific constrcution variable + that you want to disply. + For example, + it's not unusual to want to verify + the external environment used to execute build commands, + to make sure that the PATH and other + environment variables are set up the way they should be. + You can do this as follows: + + </para> + + <programlisting> + env = Environment() + print env.Dump('ENV') + </programlisting> + + <para> + + Which might display the following when executed on a POSIX system: + + </para> + + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + {'PATH': '/usr/local/bin:/opt/bin:/bin:/usr/bin'} + scons: done reading SConscript files. + scons: Building targets ... + scons: `.' is up to date. + scons: done building targets. + </screen> + + <para> + + And the following when executed on a Windows system: + + </para> + + <screen> + C:\><userinput>scons</userinput> + scons: Reading SConscript files ... + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + { 'PATH': 'C:/WINDOWS\\System32', + 'PATHEXT': '.COM;.EXE;.BAT;.CMD', + 'SystemRoot': 'C:/WINDOWS'} + scons: done reading SConscript files. + scons: Building targets ... + scons: `.' is up to date. + scons: done building targets. + </screen> + + </section> + + <section> + + <title>What Dependencies Does &SCons; Know About? the &tree; Option</title> + + <para> + + Sometimes the best way to try to figure out what + &SCons; is doing is simply to take a look at the + dependency graph that it constructs + based on your &SConscript; files. + The <literal>--tree</literal> option + will display all or part of the + &SCons; dependency graph in an + "ASCII art" graphical format + that shows the dependency hierarchy. + + </para> + + <para> + + For example, given the following input &SConstruct; file: + + </para> + + <programlisting> + env = Environment(CPPPATH = ['.']) + env.Program('prog', ['f1.c', 'f2.c', 'f3.c']) + </programlisting> + + <para> + + Running &SCons; with the <literal>--tree=all</literal> + option yields: + + </para> + + <screen> + % <userinput>scons -Q --tree=all</userinput> + cc -o f1.o -c -I. f1.c + cc -o f2.o -c -I. f2.c + cc -o f3.o -c -I. f3.c + cc -o prog f1.o f2.o f3.o + +-. + +-SConstruct + +-f1.c + +-f1.o + | +-f1.c + | +-inc.h + +-f2.c + +-f2.o + | +-f2.c + | +-inc.h + +-f3.c + +-f3.o + | +-f3.c + | +-inc.h + +-inc.h + +-prog + +-f1.o + | +-f1.c + | +-inc.h + +-f2.o + | +-f2.c + | +-inc.h + +-f3.o + +-f3.c + +-inc.h + </screen> + + <para> + + The tree will also be printed when the + <literal>-n</literal> (no execute) option is used, + which allows you to examine the dependency graph + for a configuration without actually + rebuilding anything in the tree. + + </para> + + <para> + + The <literal>--tree</literal> option only prints + the dependency graph for the specified targets + (or the default target(s) if none are specified on the command line). + So if you specify a target like <filename>f2.o</filename> + on the command line, + the <literal>--tree</literal> option will only + print the dependency graph for that file: + + </para> + + <screen> + % <userinput>scons -Q --tree=all f2.o</userinput> + cc -o f2.o -c -I. f2.c + +-f2.o + +-f2.c + +-inc.h + </screen> + + <para> + + This is, of course, useful for + restricting the output from a very large + build configuration to just a + portion in which you're interested. + Multiple targets are fine, + in which case a tree will be printed + for each specified target: + + </para> + + <screen> + % <userinput>scons -Q --tree=all f1.o f3.o</userinput> + cc -o f1.o -c -I. f1.c + +-f1.o + +-f1.c + +-inc.h + cc -o f3.o -c -I. f3.c + +-f3.o + +-f3.c + +-inc.h + </screen> + + <para> + + The <literal>status</literal> argument may be used + to tell &SCons; to print status information about + each file in the dependency graph: + + </para> + + <screen> + % <userinput>scons -Q --tree=status</userinput> + cc -o f1.o -c -I. f1.c + cc -o f2.o -c -I. f2.c + cc -o f3.o -c -I. f3.c + cc -o prog f1.o f2.o f3.o + E = exists + R = exists in repository only + b = implicit builder + B = explicit builder + S = side effect + P = precious + A = always build + C = current + N = no clean + H = no cache + + [E b ]+-. + [E C ] +-SConstruct + [E C ] +-f1.c + [E B C ] +-f1.o + [E C ] | +-f1.c + [E C ] | +-inc.h + [E C ] +-f2.c + [E B C ] +-f2.o + [E C ] | +-f2.c + [E C ] | +-inc.h + [E C ] +-f3.c + [E B C ] +-f3.o + [E C ] | +-f3.c + [E C ] | +-inc.h + [E C ] +-inc.h + [E B C ] +-prog + [E B C ] +-f1.o + [E C ] | +-f1.c + [E C ] | +-inc.h + [E B C ] +-f2.o + [E C ] | +-f2.c + [E C ] | +-inc.h + [E B C ] +-f3.o + [E C ] +-f3.c + [E C ] +-inc.h + </screen> + + <para> + + Note that <literal>--tree=all,status</literal> is equivalent; + the <literal>all</literal> + is assumed if only <literal>status</literal> is present. + As an alternative to <literal>all</literal>, + you can specify <literal>--tree=derived</literal> + to have &SCons; only print derived targets + in the tree output, + skipping source files + (like <filename>.c</filename> and <filename>.h</filename> files): + + </para> + + <screen> + % <userinput>scons -Q --tree=derived</userinput> + cc -o f1.o -c -I. f1.c + cc -o f2.o -c -I. f2.c + cc -o f3.o -c -I. f3.c + cc -o prog f1.o f2.o f3.o + +-. + +-f1.o + +-f2.o + +-f3.o + +-prog + +-f1.o + +-f2.o + +-f3.o + </screen> + + <para> + + You can use the <literal>status</literal> + modifier with <literal>derived</literal> as well: + + </para> + + <screen> + % <userinput>scons -Q --tree=derived,status</userinput> + cc -o f1.o -c -I. f1.c + cc -o f2.o -c -I. f2.c + cc -o f3.o -c -I. f3.c + cc -o prog f1.o f2.o f3.o + E = exists + R = exists in repository only + b = implicit builder + B = explicit builder + S = side effect + P = precious + A = always build + C = current + N = no clean + H = no cache + + [E b ]+-. + [E B C ] +-f1.o + [E B C ] +-f2.o + [E B C ] +-f3.o + [E B C ] +-prog + [E B C ] +-f1.o + [E B C ] +-f2.o + [E B C ] +-f3.o + </screen> + + <para> + + Note that the order of the <literal>--tree=</literal> + arguments doesn't matter; + <literal>--tree=status,derived</literal> is + completely equivalent. + + </para> + + <para> + + The default behavior of the <literal>--tree</literal> option + is to repeat all of the dependencies each time the library dependency + (or any other dependency file) is encountered in the tree. + If certain target files share other target files, + such as two programs that use the same library: + + </para> + + <programlisting> + env = Environment(CPPPATH = ['.'], + LIBS = ['foo'], + LIBPATH = ['.']) + env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) + env.Program('prog1.c') + env.Program('prog2.c') + </programlisting> + + <para> + + Then there can be a <emphasis>lot</emphasis> of repetition in the + <literal>--tree=</literal> output: + + </para> + + <screen> + % <userinput>scons -Q --tree=all</userinput> + cc -o f1.o -c -I. f1.c + cc -o f2.o -c -I. f2.c + cc -o f3.o -c -I. f3.c + ar rc libfoo.a f1.o f2.o f3.o + ranlib libfoo.a + cc -o prog1.o -c -I. prog1.c + cc -o prog1 prog1.o -L. -lfoo + cc -o prog2.o -c -I. prog2.c + cc -o prog2 prog2.o -L. -lfoo + +-. + +-SConstruct + +-f1.c + +-f1.o + | +-f1.c + | +-inc.h + +-f2.c + +-f2.o + | +-f2.c + | +-inc.h + +-f3.c + +-f3.o + | +-f3.c + | +-inc.h + +-inc.h + +-libfoo.a + | +-f1.o + | | +-f1.c + | | +-inc.h + | +-f2.o + | | +-f2.c + | | +-inc.h + | +-f3.o + | +-f3.c + | +-inc.h + +-prog1 + | +-prog1.o + | | +-prog1.c + | | +-inc.h + | +-libfoo.a + | +-f1.o + | | +-f1.c + | | +-inc.h + | +-f2.o + | | +-f2.c + | | +-inc.h + | +-f3.o + | +-f3.c + | +-inc.h + +-prog1.c + +-prog1.o + | +-prog1.c + | +-inc.h + +-prog2 + | +-prog2.o + | | +-prog2.c + | | +-inc.h + | +-libfoo.a + | +-f1.o + | | +-f1.c + | | +-inc.h + | +-f2.o + | | +-f2.c + | | +-inc.h + | +-f3.o + | +-f3.c + | +-inc.h + +-prog2.c + +-prog2.o + +-prog2.c + +-inc.h + </screen> + + <para> + + In a large configuration with many internal libraries + and include files, + this can very quickly lead to huge output trees. + To help make this more manageable, + a <literal>prune</literal> modifier may + be added to the option list, + in which case &SCons; + will print the name of a target that has + already been visited during the tree-printing + in <literal>[square brackets]</literal> + as an indication that the dependencies + of the target file may be found + by looking farther up the tree: + + </para> + + <screen> + % <userinput>scons -Q --tree=prune</userinput> + cc -o f1.o -c -I. f1.c + cc -o f2.o -c -I. f2.c + cc -o f3.o -c -I. f3.c + ar rc libfoo.a f1.o f2.o f3.o + ranlib libfoo.a + cc -o prog1.o -c -I. prog1.c + cc -o prog1 prog1.o -L. -lfoo + cc -o prog2.o -c -I. prog2.c + cc -o prog2 prog2.o -L. -lfoo + +-. + +-SConstruct + +-f1.c + +-f1.o + | +-f1.c + | +-inc.h + +-f2.c + +-f2.o + | +-f2.c + | +-inc.h + +-f3.c + +-f3.o + | +-f3.c + | +-inc.h + +-inc.h + +-libfoo.a + | +-[f1.o] + | +-[f2.o] + | +-[f3.o] + +-prog1 + | +-prog1.o + | | +-prog1.c + | | +-inc.h + | +-[libfoo.a] + +-prog1.c + +-[prog1.o] + +-prog2 + | +-prog2.o + | | +-prog2.c + | | +-inc.h + | +-[libfoo.a] + +-prog2.c + +-[prog2.o] + </screen> + + <para> + + Like the <literal>status</literal> keyword, + the <literal>prune</literal> argument by itself + is equivalent to <literal>--tree=all,prune</literal>. + + </para> + + </section> + + <section> + + <title>How is &SCons; Constructing the Command Lines It Executes? the &debug-presub; Option</title> + + <para> + + Sometimes it's useful to look at the + pre-substitution string + that &SCons; uses to generate + the command lines it executes. + This can be done with the &debug-presub; option: + + </para> + + + + <!-- + + Have to capture output here, otherwise the - -debug=presub output + shows the Python functions from the sconsdoc.py execution wrapper + used to generate this manual, not the underlying command-line strings. + + <scons_output example="presub"> + <scons_output_command>scons -Q - -debug=presub</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q --debug=presub</userinput> + Building prog.o with action: + $CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCOMCOM $SOURCES + cc -o prog.o -c -I. prog.c + Building prog with action: + $SMART_LINKCOM + cc -o prog prog.o + </screen> + + </section> + + <section> + + <title>Where is &SCons; Searching for Libraries? the &debug-findlibs; Option</title> + + <para> + + To get some insight into what library names + &SCons; is searching for, + and in which directories it is searching, + Use the <literal>--debug=findlibs</literal> option. + Given the following input &SConstruct; file: + + </para> + + <programlisting> + env = Environment(LIBPATH = ['libs1', 'libs2']) + env.Program('prog.c', LIBS=['foo', 'bar']) + </programlisting> + + <para> + + And the libraries <filename>libfoo.a</filename> + and <filename>libbar.a</filename> + in <filename>libs1</filename> and <filename>libs2</filename>, + respectively, + use of the <literal>--debug=findlibs</literal> option yields: + + </para> + + <screen> + % <userinput>scons -Q --debug=findlibs</userinput> + findlibs: looking for 'libfoo.a' in 'libs1' ... + findlibs: ... FOUND 'libfoo.a' in 'libs1' + findlibs: looking for 'libfoo.so' in 'libs1' ... + findlibs: looking for 'libfoo.so' in 'libs2' ... + findlibs: looking for 'libbar.a' in 'libs1' ... + findlibs: looking for 'libbar.a' in 'libs2' ... + findlibs: ... FOUND 'libbar.a' in 'libs2' + findlibs: looking for 'libbar.so' in 'libs1' ... + findlibs: looking for 'libbar.so' in 'libs2' ... + cc -o prog.o -c prog.c + cc -o prog prog.o -Llibs1 -Llibs2 -lfoo -lbar + </screen> + + </section> + + <!-- + + <section> + + <title>What Implicit Dependencies Did the &SCons; Scanner find? the &debug-includes; Option</title> + + <para> + + XXX explain the - - debug=includes option + + </para> + + <scons_example name="includes"> + <file name="SConstruct" printme="1"> + env = Environment(CPPPATH = ['inc1', 'inc2']) + env.Program('prog.c') + </file> + <file name="prog.c"> + #include "file1.h" + #include "file2.h" + prog.c + </file> + <file name="inc1/file1.h"> + inc1/file1.h + </file> + <file name="inc2/file2.h"> + inc2/file2.h + </file> + </scons_example> + + <scons_output example="includes"> + <scons_output_command>scons -Q - - debug=includes prog</scons_output_command> + </scons_output> + + </section> + + --> + + <section> + + <title>Where is &SCons; Blowing Up? the &debug-stacktrace; Option</title> + + <para> + + In general, &SCons; tries to keep its error + messages short and informative. + That means we usually try to avoid showing + the stack traces that are familiar + to experienced Python programmers, + since they usually contain much more + information than is useful to most people. + + </para> + + <para> + + For example, the following &SConstruct; file: + + </para> + + <programlisting> + Program('prog.c') + </programlisting> + + <para> + + Generates the following error if the + <filename>prog.c</filename> file + does not exist: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + scons: *** [prog.o] Source `prog.c' not found, needed by target `prog.o'. + </screen> + + <para> + + In this case, + the error is pretty obvious. + But if it weren't, + and you wanted to try to get more information + about the error, + the &debug-stacktrace; option + would show you exactly where in the &SCons; source code + the problem occurs: + + </para> + + <screen> + % <userinput>scons -Q --debug=stacktrace</userinput> + scons: *** [prog.o] Source `prog.c' not found, needed by target `prog.o'. + scons: internal stack trace: + File "bootstrap/src/engine/SCons/Job.py", line 197, in start + File "bootstrap/src/engine/SCons/Script/Main.py", line 167, in prepare + File "bootstrap/src/engine/SCons/Taskmaster.py", line 190, in prepare + File "bootstrap/src/engine/SCons/Executor.py", line 397, in prepare + </screen> + + <para> + + Of course, if you do need to dive into the &SCons; source code, + we'd like to know if, or how, + the error messages or troubleshooting options + could have been improved to avoid that. + Not everyone has the necessary time or + Python skill to dive into the source code, + and we'd like to improve &SCons; + for those people as well... + + </para> + + </section> + + <section> + + <title>How is &SCons; Making Its Decisions? the &taskmastertrace; Option</title> + + <para> + + The internal &SCons; subsystem that handles walking + the dependency graph + and controls the decision-making about what to rebuild + is the <literal>Taskmaster</literal>. + &SCons; supports a <literal>--taskmastertrace</literal> + option that tells the Taskmaster to print + information about the children (dependencies) + of the various Nodes on its walk down the graph, + which specific dependent Nodes are being evaluated, + and in what order. + + </para> + + <para> + + The <literal>--taskmastertrace</literal> option + takes as an argument the name of a file in + which to put the trace output, + with <filename>-</filename> (a single hyphen) + indicating that the trace messages + should be printed to the standard output: + + </para> + + <programlisting> + env = Environment(CPPPATH = ['.']) + env.Program('prog.c') + </programlisting> + + <screen> + % <userinput>scons -Q --taskmastertrace=- prog</userinput> + + Taskmaster: Looking for a node to evaluate + Taskmaster: Considering node <no_state 0 'prog'> and its children: + Taskmaster: <no_state 0 'prog.o'> + Taskmaster: adjusted ref count: <pending 1 'prog'>, child 'prog.o' + Taskmaster: Considering node <no_state 0 'prog.o'> and its children: + Taskmaster: <no_state 0 'prog.c'> + Taskmaster: <no_state 0 'inc.h'> + Taskmaster: adjusted ref count: <pending 1 'prog.o'>, child 'prog.c' + Taskmaster: adjusted ref count: <pending 2 'prog.o'>, child 'inc.h' + Taskmaster: Considering node <no_state 0 'prog.c'> and its children: + Taskmaster: Evaluating <pending 0 'prog.c'> + + Task.make_ready_current(): node <pending 0 'prog.c'> + Task.prepare(): node <up_to_date 0 'prog.c'> + Task.executed_with_callbacks(): node <up_to_date 0 'prog.c'> + Task.postprocess(): node <up_to_date 0 'prog.c'> + Task.postprocess(): removing <up_to_date 0 'prog.c'> + Task.postprocess(): adjusted parent ref count <pending 1 'prog.o'> + + Taskmaster: Looking for a node to evaluate + Taskmaster: Considering node <no_state 0 'inc.h'> and its children: + Taskmaster: Evaluating <pending 0 'inc.h'> + + Task.make_ready_current(): node <pending 0 'inc.h'> + Task.prepare(): node <up_to_date 0 'inc.h'> + Task.executed_with_callbacks(): node <up_to_date 0 'inc.h'> + Task.postprocess(): node <up_to_date 0 'inc.h'> + Task.postprocess(): removing <up_to_date 0 'inc.h'> + Task.postprocess(): adjusted parent ref count <pending 0 'prog.o'> + + Taskmaster: Looking for a node to evaluate + Taskmaster: Considering node <pending 0 'prog.o'> and its children: + Taskmaster: <up_to_date 0 'prog.c'> + Taskmaster: <up_to_date 0 'inc.h'> + Taskmaster: Evaluating <pending 0 'prog.o'> + + Task.make_ready_current(): node <pending 0 'prog.o'> + Task.prepare(): node <executing 0 'prog.o'> + Task.execute(): node <executing 0 'prog.o'> + cc -o prog.o -c -I. prog.c + Task.executed_with_callbacks(): node <executing 0 'prog.o'> + Task.postprocess(): node <executed 0 'prog.o'> + Task.postprocess(): removing <executed 0 'prog.o'> + Task.postprocess(): adjusted parent ref count <pending 0 'prog'> + + Taskmaster: Looking for a node to evaluate + Taskmaster: Considering node <pending 0 'prog'> and its children: + Taskmaster: <executed 0 'prog.o'> + Taskmaster: Evaluating <pending 0 'prog'> + + Task.make_ready_current(): node <pending 0 'prog'> + Task.prepare(): node <executing 0 'prog'> + Task.execute(): node <executing 0 'prog'> + cc -o prog prog.o + Task.executed_with_callbacks(): node <executing 0 'prog'> + Task.postprocess(): node <executed 0 'prog'> + + Taskmaster: Looking for a node to evaluate + Taskmaster: No candidate anymore. + </screen> + + <para> + + The <literal>--taskmastertrace</literal> option + doesn't provide information about the actual + calculations involved in deciding if a file is up-to-date, + but it does show all of the dependencies + it knows about for each Node, + and the order in which those dependencies are evaluated. + This can be useful as an alternate way to determine + whether or not your &SCons; configuration, + or the implicit dependency scan, + has actually identified all the correct dependencies + you want it to. + + </para> + + </section> + + <!-- + + <section> + + <title>Where Are My Build Bottlenecks? the &profile; Option</title> + + <para> + + XXX explain the - - profile= option + + </para> + + </section> + + --> + + <!-- + + <section> + <title>Troubleshooting Shared Caching: the &cache-debug; Option</title> + + <para> + + XXX describe the - - cache-debug option + XXX maybe point to the caching.in chapter? + + </para> + + </section> + + --> diff --git a/doc/user/variables.in b/doc/user/variables.in new file mode 100644 index 0000000..85fb9cd --- /dev/null +++ b/doc/user/variables.in @@ -0,0 +1,56 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + +This appendix contains descriptions of all of the +construction variables that are <emphasis>potentially</emphasis> +available "out of the box" in this version of SCons. +Whether or not setting a construction variable +in a construction environment +will actually have an effect depends on +whether any of the Tools and/or Builders +that use the variable have been +included in the construction environment. + +</para> + +<para> + +In this appendix, we have +appended the initial <envar>$</envar> +(dollar sign) to the beginning of each +variable name when it appears in the text, +but left off the dollar sign +in the left-hand column +where the name appears for each entry. + +</para> + +<variablelist> + +&variables-gen; + +</variablelist> diff --git a/doc/user/variables.xml b/doc/user/variables.xml new file mode 100644 index 0000000..85fb9cd --- /dev/null +++ b/doc/user/variables.xml @@ -0,0 +1,56 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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> + +This appendix contains descriptions of all of the +construction variables that are <emphasis>potentially</emphasis> +available "out of the box" in this version of SCons. +Whether or not setting a construction variable +in a construction environment +will actually have an effect depends on +whether any of the Tools and/or Builders +that use the variable have been +included in the construction environment. + +</para> + +<para> + +In this appendix, we have +appended the initial <envar>$</envar> +(dollar sign) to the beginning of each +variable name when it appears in the text, +but left off the dollar sign +in the left-hand column +where the name appears for each entry. + +</para> + +<variablelist> + +&variables-gen; + +</variablelist> diff --git a/doc/user/variants.in b/doc/user/variants.in new file mode 100644 index 0000000..696e174 --- /dev/null +++ b/doc/user/variants.in @@ -0,0 +1,151 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 Variant builds + +=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> + + The &variant_dir; keyword argument of + the &SConscript; function provides everything + we need to show how easy it is to create + variant builds using &SCons;. + Suppose, for example, that we want to + build a program for both Windows and Linux platforms, + but that we want to build it in a shared directory + with separate side-by-side build directories + for the Windows and Linux versions of the program. + + </para> + + <scons_example name="ex_variants"> + <file name="SConstruct" printme="1"> + platform = ARGUMENTS.get('OS', Platform()) + + include = "#export/$PLATFORM/include" + lib = "#export/$PLATFORM/lib" + bin = "#export/$PLATFORM/bin" + + env = Environment(PLATFORM = platform, + BINDIR = bin, + INCDIR = include, + LIBDIR = lib, + CPPPATH = [include], + LIBPATH = [lib], + LIBS = 'world') + + Export('env') + + env.SConscript('src/SConscript', variant_dir='build/$PLATFORM') + </file> + <directory name="src"></directory> + <directory name="src/hello"></directory> + <directory name="src/world"></directory> + <file name="src/SConscript"> + Import('env') + SConscript('hello/SConscript') + SConscript('world/SConscript') + </file> + <file name="src/hello/SConscript"> + Import('env') + hello = env.Program('hello.c') + env.Install('$BINDIR', hello) + </file> + <file name="src/hello/hello.c"> + #include "world.h" + int main(int argc, char *argv[]) { printf "hello.c\n"; world(); } + </file> + <file name="src/world/SConscript"> + Import('env') + world = env.Library('world.c') + env.Install('$LIBDIR', world) + env.Install('$INCDIR', 'world.h') + </file> + <file name="src/world/world.h"> + #define STRING "world.h" + extern int world(); + </file> + <file name="src/world/world.c"> + int world() { printf "world.c\n"; } + </file> + </scons_example> + + <para> + + This SConstruct file, + when run on a Linux system, yields: + + </para> + + <scons_output example="ex_variants" os="posix"> + <scons_output_command>scons -Q OS=linux</scons_output_command> + </scons_output> + + <para> + + The same SConstruct file on Windows would build: + + </para> + + <scons_output example="ex_variants" os="win32"> + <scons_output_command>scons -Q OS=windows</scons_output_command> + </scons_output> + + <!-- + + <scons_example name="ex_var2"> + <file name="SConstruct" printme="1"> + env = Environment(OS = ARGUMENTS.get('OS')) + for os in ['newell', 'post']: + SConscript('src/SConscript', variant_dir='build/' + os) + </file> + </scons_example> + + <scons_output example="ex_var2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> diff --git a/doc/user/variants.xml b/doc/user/variants.xml new file mode 100644 index 0000000..016202a --- /dev/null +++ b/doc/user/variants.xml @@ -0,0 +1,146 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + 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 Variant builds + +=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> + + The &variant_dir; keyword argument of + the &SConscript; function provides everything + we need to show how easy it is to create + variant builds using &SCons;. + Suppose, for example, that we want to + build a program for both Windows and Linux platforms, + but that we want to build it in a shared directory + with separate side-by-side build directories + for the Windows and Linux versions of the program. + + </para> + + <programlisting> + platform = ARGUMENTS.get('OS', Platform()) + + include = "#export/$PLATFORM/include" + lib = "#export/$PLATFORM/lib" + bin = "#export/$PLATFORM/bin" + + env = Environment(PLATFORM = platform, + BINDIR = bin, + INCDIR = include, + LIBDIR = lib, + CPPPATH = [include], + LIBPATH = [lib], + LIBS = 'world') + + Export('env') + + env.SConscript('src/SConscript', variant_dir='build/$PLATFORM') + </programlisting> + + <para> + + This SConstruct file, + when run on a Linux system, yields: + + </para> + + <screen> + % <userinput>scons -Q OS=linux</userinput> + Install file: "build/linux/world/world.h" as "export/linux/include/world.h" + cc -o build/linux/hello/hello.o -c -Iexport/linux/include build/linux/hello/hello.c + cc -o build/linux/world/world.o -c -Iexport/linux/include build/linux/world/world.c + ar rc build/linux/world/libworld.a build/linux/world/world.o + ranlib build/linux/world/libworld.a + Install file: "build/linux/world/libworld.a" as "export/linux/lib/libworld.a" + cc -o build/linux/hello/hello build/linux/hello/hello.o -Lexport/linux/lib -lworld + Install file: "build/linux/hello/hello" as "export/linux/bin/hello" + </screen> + + <para> + + The same SConstruct file on Windows would build: + + </para> + + <screen> + C:\><userinput>scons -Q OS=windows</userinput> + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + Install file: "build/windows/world/world.h" as "export/windows/include/world.h" + cl /Fobuild\windows\hello\hello.obj /c build\windows\hello\hello.c /nologo /Iexport\windows\include + cl /Fobuild\windows\world\world.obj /c build\windows\world\world.c /nologo /Iexport\windows\include + lib /nologo /OUT:build\windows\world\world.lib build\windows\world\world.obj + Install file: "build/windows/world/world.lib" as "export/windows/lib/world.lib" + link /nologo /OUT:build\windows\hello\hello.exe /LIBPATH:export\windows\lib world.lib build\windows\hello\hello.obj + Install file: "build/windows/hello/hello.exe" as "export/windows/bin/hello.exe" + </screen> + + <!-- + + <scons_example name="ex_var2"> + <file name="SConstruct" printme="1"> + env = Environment(OS = ARGUMENTS.get('OS')) + for os in ['newell', 'post']: + SConscript('src/SConscript', variant_dir='build/' + os) + </file> + </scons_example> + + <scons_output example="ex_var2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> |