diff options
Diffstat (limited to 'doc/user/depends.xml')
-rw-r--r-- | doc/user/depends.xml | 917 |
1 files changed, 917 insertions, 0 deletions
diff --git a/doc/user/depends.xml b/doc/user/depends.xml new file mode 100644 index 0000000..9e055ee --- /dev/null +++ b/doc/user/depends.xml @@ -0,0 +1,917 @@ +<!-- + + __COPYRIGHT__ + + 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 the real point of a build tool like &SCons; + is to rebuild only the necessary things + when source files change--or, put another way, + &SCons; should <emphasis>not</emphasis> + waste time rebuilding things that have already been built. + You can see this at work simply be 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 a Source File Has Changed: the &SourceSignatures; Function</title> + + <para> + + The other side of avoiding unnecessary rebuilds + is the fundamental build tool behavior + of <emphasis>rebuilding</emphasis> + things when a source file changes, + so that the built software is up to date. + &SCons; keeps track of this through a + &signature; for each source file, + and allows you to configure + whether you want to use the source + file contents or the modification time (timestamp) + as the signature. + + </para> + + <section> + <title>MD5 Source File Signatures</title> + + <para> + + By default, + &SCons; keeps track of whether a source file has changed + based on the file's contents, + not the 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 &SourceSignatures; function as follows: + + </para> + + <programlisting> + Program('hello.c') + SourceSignatures('MD5') + </programlisting> + + </section> + + <section> + <title>Source File Time Stamps</title> + + <para> + + If you prefer, you can + configure &SCons; to use the modification time + of source files, + not the file contents, + when deciding if something needs to be rebuilt. + To do this, call the &SourceSignatures; + function as follows: + + </para> + + <programlisting> + Program('hello.c') + SourceSignatures('timestamp') + </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> + + </section> + + </section> + + <section> + <title>Deciding When a Target File Has Changed: the &TargetSignatures; Function</title> + + <para> + + As you've just seen, + &SCons; uses signatures to decide whether a + target file is up to date or must be rebuilt. + When a target file depends on another target file, + &SCons; allows you to configure separately + how the signatures of "intermediate" target files + are used when deciding if a dependent target file + must be rebuilt. + + </para> + + <section> + <title>Build Signatures</title> + + <para> + + Modifying a source file + will cause not only its direct target file to be rebuilt, + but also the target file(s) + that depend on that direct target file. + In our example, + changing the contents of the &hello_c; file causes + the &hello_o; file to be rebuilt, + which in turn causes the + &hello; program to be rebuilt: + + </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> + + What's not obvious, though, + is that &SCons; internally handles the signature of + the target file(s) + (&hello_o; in the above example) + differently from the signature of the source file + (&hello_c;). + By default, + &SCons; tracks whether a target file must be rebuilt + by using a &buildsignature; + that consists of the combined + signatures of all the files + that go into making the target file. + This is efficient because + the accumulated signatures + actually give &SCons; all of the + information it needs + to decide if the target file is out of date. + + </para> + + <para> + + If you wish, you can + specify this default behavior + (build signatures) explicitly + using the &TargetSignatures; function: + + </para> + + <programlisting> + Program('hello.c') + TargetSignatures('build') + </programlisting> + + </section> + + <section> + <title>File Contents</title> + + <para> + + Sometimes a source file can be 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. + If so, then any other target files + that depend on such a built-but-not-changed target + file actually need not be rebuilt. + You can make &SCons; + realize that it does not need to rebuild + a dependent target file in this situation + using the &TargetSignatures; function as follows: + + </para> + + <programlisting> + Program('hello.c') + TargetSignatures('content') + </programlisting> + + <para> + + So if, for example, + a user were to only change a comment in a 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; has + "short-circuited" any dependent builds + when it realizes that a target file + has been rebuilt to exactly the same file as the last build. + So configured, + &SCons; does take some extra processing time + to scan the contents of the target (&hello_o;) file, + but this may save time + if the rebuild that was avoided + would have been very time-consuming and expensive. + + </para> + + </section> + + </section> + + <section> + <title>Implicit Dependencies: The &cv-CPPPATH; Construction Variable</title> + + <para> + + Now suppose that our "Hello, World!" program + actually has a <literal>#include</literal> line + to include the &hello_h; file in the compilation: + + </para> + + <programlisting> + #include <hello.h> + int + main() + { + printf("Hello, %s!\n", string); + } + </programlisting> + + <para> + + And, for completeness, the &hello_h; file looks like this: + + </para> + + + <programlisting> + #define string "world" + </programlisting> + + <para> + + In this case, we want &SCons; to recognize that, + if the contents of the &hello_h; file change, + the &hello; program must be recompiled. + To do this, we need to modify the + &SConstruct; file like so: + + </para> + + + <programlisting> + Program('hello.c', CPPPATH = '.') + </programlisting> + + <para> + + The &cv-link-CPPPATH; value + tells &SCons; to look in the current directory + (<literal>'.'</literal>) + for any files included by C source files + (<filename>.c</filename> or <filename>.h</filename> files). + With this assignment in the &SConstruct; file: + + </para> + + <screen> + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c -I. hello.c + cc -o hello hello.o + % <userinput>scons -Q hello</userinput> + scons: `hello' is up to date. + % <userinput>edit hello.h</userinput> + [CHANGE THE CONTENTS OF hello.h] + % <userinput>scons -Q hello</userinput> + cc -o hello.o -c -I. hello.c + cc -o hello hello.o + </screen> + + <para> + + First, notice that &SCons; + added the <literal>-I.</literal> argument + from the &cv-CPPPATH; variable + so that the compilation would find the + &hello_h; file in the local directory. + + </para> + + <para> + + Second, realize that &SCons; knows that the &hello; + program must be rebuilt + because it scans the contents of + the &hello_c; file + for the <literal>#include</literal> lines that indicate + another file is being included in the compilation. + &SCons; records these as + <emphasis>implicit dependencies</emphasis> + of the target file, + Consequently, + when the &hello_h; file changes, + &SCons; realizes that the &hello_c; file includes it, + and rebuilds the resulting &hello; program + that depends on both the &hello_c; and &hello_h; files. + + </para> + + <para> + + Like the &cv-link-LIBPATH; variable, + the &cv-CPPPATH; variable + may be a list of directories, + or a string separated by + the system-specific path separate 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> + cl /nologo /Iinclude /I\home\project\inc /c hello.c /Fohello.obj + 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>Ignoring Dependencies: the &Ignore; Method</title> + + <para> + + Sometimes it makes sense + to not rebuild a program, + even if a dependency file changes. + In this case, + you would tell &SCons; specifically + to ignore a dependency as follows: + + </para> + + <programlisting> + hello = Program('hello.c') + Ignore(hello, 'hello.h') + </programlisting> + + <!-- XXX mention that you can use arrays 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 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') + Ignore(hello, '/usr/include/stdio.h') + </programlisting> + + </section> + + <section> + <title>Explicit Dependencies: the &Depends; Method</title> + + <para> + + On the other hand, + 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> + + </section> + + <section> + <title>The &AlwaysBuild; Method</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> + + --> |