summaryrefslogtreecommitdiff
path: root/doc/user/depends.xml
diff options
context:
space:
mode:
Diffstat (limited to 'doc/user/depends.xml')
-rw-r--r--doc/user/depends.xml1776
1 files changed, 1776 insertions, 0 deletions
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 &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>
+
+ </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 &lt;hello.h&gt;
+ 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 "&lt;stdin&gt;", line 67, in __call__
+
+ scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly
+ File "&lt;stdin&gt;", 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 &lt;foo.h&gt;
+ #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>
+
+ -->