summaryrefslogtreecommitdiff
path: root/doc/user/depends.in
diff options
context:
space:
mode:
authorLuca Falavigna <dktrkranz@debian.org>2014-04-26 15:11:58 +0200
committerLuca Falavigna <dktrkranz@debian.org>2014-04-26 15:11:58 +0200
commit140d836e9cd54fb67b969fd82ef7ed19ba574d40 (patch)
tree0df3e32ee39603d43f9b90fd2f2e1f7cce4249d4 /doc/user/depends.in
parentcb3425abe0bc2d05caf401ca24b82a25a81f009d (diff)
Imported Upstream version 2.3.1upstream/2.3.1
Diffstat (limited to 'doc/user/depends.in')
-rw-r--r--doc/user/depends.in1872
1 files changed, 0 insertions, 1872 deletions
diff --git a/doc/user/depends.in b/doc/user/depends.in
deleted file mode 100644
index de2e11c..0000000
--- a/doc/user/depends.in
+++ /dev/null
@@ -1,1872 +0,0 @@
-<!--
-
- Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 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">
- Object('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.o</scons_output_command>
- <scons_output_command>touch hello.c</scons_output_command>
- <scons_output_command>scons -Q hello.o</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>
- Object('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">
- Object('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.o</scons_output_command>
- <scons_output_command>touch -t 198901010000 hello.c</scons_output_command>
- <scons_output_command>scons -Q hello.o</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 be 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 &target;.
- 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 &target; 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 &target; 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>
-
- <para>
-
- Another thing to look out for is the fact that the three
- attributes above may not be present at the time of the first run.
- Without any prior build, no targets have been created and no
- <filename>.sconsign</filename> DB file exists yet.
- So, you should always check whether the
- <varname>prev_ni</varname> attribute in question is available.
-
- </para>
-
- <para>
-
- We finally present a small example for a
- <varname>csig</varname>-based decider function. Note how the
- signature information for the <varname>dependency</varname> file
- has to get initialized via <function>get_csig</function>
- during each function call (this is mandatory!).
-
- </para>
-
- <sconstruct>
- env = Environment()
-
- def config_file_decider(dependency, target, prev_ni):
- import os.path
-
- # We always have to init the .csig value...
- dep_csig = dependency.get_csig()
- # .csig may not exist, because no target was built yet...
- if 'csig' not in dir(prev_ni):
- return True
- # Target file may not exist yet
- if not os.path.exists(str(target.abspath)):
- return True
- if dep_csig != prev_ni.csig:
- # Some change on source file => update installed one
- return True
- return False
-
- def update_file():
- f = open("test.txt","a")
- f.write("some line\n")
- f.close()
-
- update_file()
-
- # Activate our own decider function
- env.Decider(config_file_decider)
-
- env.Install("install","test.txt")
- </sconstruct>
-
- </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.
- These functions have been officially deprecated
- as &SCons; version 2.0,
- and 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 older &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 &lt;hello.h&gt;
- 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 &lt;foo.h&gt;
- #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 &lt;foo.h&gt;
- #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 &lt;foo.h&gt;
- #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_obj=Object('hello.c')
- hello = Program(hello_obj)
- Ignore(hello_obj, '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 the <filename>version.o</filename> file
- 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 hello</scons_output_command>
- <scons_output_command>sleep 1</scons_output_command>
- <scons_output_command>scons -Q hello</scons_output_command>
- <scons_output_command>sleep 1</scons_output_command>
- <scons_output_command>scons -Q hello</scons_output_command>
- </scons_output>
-
- <para>
-
- (Note that for the above example to work,
- we &sleep; for one second in between each run,
- so that the &SConstruct; file will create a
- <filename>version.c</filename> file with a time string
- that's one second later than the previous run.)
-
- </para>
-
- <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 only
- re-linking the <filename>hello</filename> executable
- when the <filename>hello.c</filename> has changed,
- even though the <filename>version.o</filename> is rebuilt
- (because the &SConstruct; file still changes the
- <filename>version.c</filename> contents directly each run):
-
- </para>
-
- <scons_output example="Requires">
- <scons_output_command>scons -Q hello</scons_output_command>
- <scons_output_command>sleep 1</scons_output_command>
- <scons_output_command>scons -Q hello</scons_output_command>
- <scons_output_command>sleep 1</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_command>sleep 1</scons_output_command>
- <scons_output_command>scons -Q hello</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>
-
- -->