From 72c578fd4b0b4a5a43e18594339ac4ff26c376dc Mon Sep 17 00:00:00 2001 From: Luca Falavigna Date: Sat, 2 Jan 2010 20:56:27 +0100 Subject: Imported Upstream version 1.2.0.d20091224 --- doc/user/depends.in | 1816 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1816 insertions(+) create mode 100644 doc/user/depends.in (limited to 'doc/user/depends.in') diff --git a/doc/user/depends.in b/doc/user/depends.in new file mode 100644 index 0000000..dfd52e3 --- /dev/null +++ b/doc/user/depends.in @@ -0,0 +1,1816 @@ + + + + + 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 not + 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: + + + + + + Program('hello.c') + + + int main() { printf("Hello, world!\n"); } + + + + + scons -Q + scons -Q + + + + + 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: + + + + + scons -Q hello + scons -Q hello + + + + + Note that &SCons; reports "...is up to date" + only for target files named explicitly on the command line, + to avoid cluttering the output. + + + +
+ Deciding When an Input File Has Changed: the &Decider; Function + + + + Another aspect of avoiding unnecessary rebuilds + is the fundamental build tool behavior + of rebuilding + 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. + + + +
+ Using MD5 Signatures to Decide if a File Has Changed + + + + 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): + + + + + scons -Q hello + touch hello.c + scons -Q hello + + + + + Even though the file's modification time has changed, + &SCons; realizes that the contents of the + &hello_c; file have not 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: + + + + + scons -Q hello + edit hello.c + scons -Q hello + + + + + Note that you can, if you wish, + specify this default behavior + (MD5 signatures) explicitly + using the &Decider; function as follows: + + + + + Program('hello.c') + Decider('MD5') + + + + + You can also use the string 'content' + as a synonym for 'MD5' + when calling the &Decider; function. + + + +
+ Ramifications of Using MD5 Signatures + + + + 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. + + + + + + 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: + + + + + scons -Q hello + edit hello.c + scons -Q hello + + + + + 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. + + + +
+ +
+ +
+ Using Time Stamps to Decide If a File Has Changed + + + + 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. + + + + + + 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 + newer + than the target file. + To do this, call the &Decider; + function as follows: + + + + + + Program('hello.c') + Decider('timestamp-newer') + + + int main() { printf("Hello, world!\n"); } + + + + + + This makes &SCons; act like &Make; + when a file's modification time is updated + (using the &touch; command, for example): + + + + + scons -Q hello + touch hello.c + scons -Q hello + + + + + And, in fact, because this behavior is the same + as the behavior of &Make;, + you can also use the string 'make' + as a synonym for 'timestamp-newer' + when calling the &Decider; function: + + + + + Program('hello.c') + Decider('make') + + + + + One drawback to using times stamps exactly like &Make; + is that if an input file's modification time suddenly + becomes older 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. + + + + + + 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 + 'timestamp-match' + when calling the &Decider; function: + + + + + + Program('hello.c') + Decider('timestamp-match') + + + int main() { printf("Hello, world!\n"); } + + + + + + When configured this way, + &SCons; will rebuild a target whenever + a source file's modification time has changed. + So if we use the touch -t + option to change the modification time of + &hello_c; to an old date (January 1, 1989), + &SCons; will still rebuild the target file: + + + + + scons -Q hello + touch -t 198901010000 hello.c + scons -Q hello + + + + + In general, the only reason to prefer + timestamp-newer + instead of + timestamp-match, + 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. + + + +
+ +
+ Deciding If a File Has Changed Using Both MD Signatures and Time Stamps + + + + 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 'MD5-timestamp' + argument as follows: + + + + + + Program('hello.c') + Decider('MD5-timestamp') + + + int main() { printf("Hello, world!\n"); } + + + + + + So configured, &SCons will still behave like + it does when using Decider('MD5'): + + + + + + + % scons -Q hello + cc -o hello.o -c hello.c + cc -o hello hello.o + % touch hello.c + % scons -Q hello + scons: `hello' is up to date. + % edit hello.c + [CHANGE THE CONTENTS OF hello.c] + % scons -Q hello + cc -o hello.o -c hello.c + cc -o hello hello.o + + + + + 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. + + + + + + The only drawback to using + Decider('MD5-timestamp') + is that &SCons; will not + 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 + Decider('MD5-timestamp') + may not be appropriate. + + + +
+ +
+ Writing Your Own Custom &Decider; Function + + + + 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. + + + + + + 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: + + + + + + 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) + + + int main() { printf("Hello, world!\n"); } + + + + + + Note that in the function definition, + the dependency + (input file) is the first argument, + and then the ⌖. + Both of these are passed to the functions as + SCons &Node; objects, + which we convert to strings using the Python + str(). + + + + + + The third argument, prev_ni, + is an object that holds the + signature or timestamp information + that was recorded about the dependency + the last time the target was built. + A prev_ni object can hold + different information, + depending on the type of thing that the + dependency argument represents. + For normal files, + the prev_ni object + has the following attributes: + + + + + + + .csig + + + + The content signature, + or MD5 checksum, of the contents of the + dependency + file the list time the ⌖ was built. + + + + + + + .size + + + + The size in bytes of the dependency + file the list time the target was built. + + + + + + + .timestamp + + + + The modification time of the dependency + file the list time the ⌖ was built. + + + + + + + + + + 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. + + + +
+ +
+ Mixing Different Ways of Deciding If a File Has Changed + + + + 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 + env.Decider + method to affect only the configuration + decisions for targets built with a + specific construction environment. + + + + + + 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: + + + + + + env1 = Environment(CPPPATH = ['.']) + env2 = env1.Clone() + env2.Decider('timestamp-match') + env1.Program('prog-MD5', 'program1.c') + env2.Program('prog-timestamp', 'program2.c') + + + #include "inc.h" + int main() { printf("Hello, world!\n"); } + + + #include "inc.h" + int main() { printf("Hello, world!\n"); } + + + #define INC 1 + + + + + + If both of the programs include the same + inc.h file, + then updating the modification time of + inc.h + (using the &touch; command) + will cause only prog-timestamp + to be rebuilt: + + + + + scons -Q + touch inc.h + scons -Q + + +
+ +
+ +
+ Older Functions for Deciding When an Input File Has Changed + + + + &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. + + + +
+ The &SourceSignatures; Function + + + + The &SourceSignatures; function is fairly straightforward, + and supports two different argument values + to configure whether source file changes should be decided + using MD5 signatures: + + + + + Program('hello.c') + SourceSignatures('MD5') + + + + + Or using time stamps: + + + + + Program('hello.c') + SourceSignatures('timestamp') + + + + + These are roughly equivalent to specifying + Decider('MD5') + or + Decider('timestamp-match'), + respectively, + although it only affects how SCons makes + decisions about dependencies on + source files--that is, + files that are not built from any other files. + + + +
+ +
+ The &TargetSignatures; Function + + + + The &TargetSignatures; function + specifies how &SCons; decides + when a target file has changed + when it is used as a + dependency of (input to) another target--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. + + 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. + + + + + + + The &TargetSignatures; function supports the same + 'MD5' and 'timestamp' + argument values that are supported by the &SourceSignatures;, + with the same meanings, but applied to target files. + That is, in the example: + + + + + Program('hello.c') + TargetSignatures('MD5') + + + + + 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: + + + + + Program('hello.c') + TargetSignatures('timestamp') + + + + + 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. + + + + + + The &TargetSignatures; function supports + two additional argument values: + 'source' and 'build'. + The 'source' 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: + + + + + Program('hello.c') + TargetSignatures('source') + SourceSignatures('timestamp') + + + + + 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. + + + + + + Lastly, the 'build' 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. + + + + + + This mimics the behavior of + build signatures + 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 + Decider('MD5-timestamp'). + + + +
+ +
+ +
+ Implicit Dependencies: The &cv-CPPPATH; Construction Variable + + + + Now suppose that our "Hello, World!" program + actually has an #include line + to include the &hello_h; file in the compilation: + + + + + + Program('hello.c', CPPPATH = '.') + + + #include <hello.h> + int + main() + { + printf("Hello, %s!\n", string); + } + + + #define string "world" + + + + + + And, for completeness, the &hello_h; file looks like this: + + + + + + + + + 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: + + + + + + + + + The &cv-link-CPPPATH; value + tells &SCons; to look in the current directory + ('.') + for any files included by C source files + (.c or .h files). + With this assignment in the &SConstruct; file: + + + + + scons -Q hello + scons -Q hello + edit hello.h + scons -Q hello + + + + + First, notice that &SCons; + added the -I. argument + from the &cv-CPPPATH; variable + so that the compilation would find the + &hello_h; file in the local directory. + + + + + + Second, realize that &SCons; knows that the &hello; + program must be rebuilt + because it scans the contents of + the &hello_c; file + for the #include lines that indicate + another file is being included in the compilation. + &SCons; records these as + implicit dependencies + 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. + + + + + + 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: + + + + + + Program('hello.c', CPPPATH = ['include', '/home/project/inc']) + + + int main() { printf("Hello, world!\n"); } + + + + + + Will look like this on POSIX or Linux: + + + + + scons -Q hello + + + + + And like this on Windows: + + + + + scons -Q hello.exe + + +
+ +
+ Caching Implicit Dependencies + + + + Scanning each file for #include 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 rebuild + 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). + + + + + + + + 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: + + + + + scons -Q --implicit-cache hello + scons -Q hello + + + + + 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: + + + + + SetOption('implicit_cache', 1) + + + + + &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 not rebuild "correctly" in the + following cases: + + + + + + + + + + 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. + + + + + + + + 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. + + + + + + +
+ The &implicit-deps-changed; Option + + + + 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: + + + + + scons -Q --implicit-deps-changed hello + scons -Q hello + + + + + In this case, &SCons; will re-scan all of the implicit dependencies + and cache updated copies of the information. + + + +
+ +
+ The &implicit-deps-unchanged; Option + + + + 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 #include lines. + In this case, + you can use the &implicit-deps-unchanged; option: + + + + + scons -Q --implicit-deps-unchanged hello + scons -Q hello + + + + + 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. + + + +
+ + + +
+ +
+ Explicit Dependencies: the &Depends; Function + + + + 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: + + + + + hello = Program('hello.c') + Depends(hello, 'other_file') + + + + + + % scons -Q hello + cc -c hello.c -o hello.o + cc -o hello hello.o + % scons -Q hello + scons: `hello' is up to date. + % edit other_file + [CHANGE THE CONTENTS OF other_file] + % scons -Q hello + cc -c hello.c -o hello.o + cc -o hello hello.o + + + + + 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): + + + + + hello = Program('hello.c') + goodbye = Program('goodbye.c') + Depends(hello, goodbye) + + + + + in which case the dependency or dependencies + will be built before the target(s): + + + + + % scons -Q hello + cc -c goodbye.c -o goodbye.o + cc -o goodbye goodbye.o + cc -c hello.c -o hello.o + cc -o hello hello.o + + +
+ +
+ Dependencies From External Files: the &ParseDepends; + Function + + + + &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. + + + + + + The following example illustrates a case where the built-in C + scanner is unable to extract the implicit dependency on a header + file. + + + + + + #define FOO_HEADER <foo.h> + #include FOO_HEADER + + int main() { + return FOO; + } + + + Program('hello', 'hello.c', CPPPATH='.') + + + #define FOO 42 + + + + + scons -Q + edit foo.h + scons -Q + + + + + Apparently, the scanner does not know about the header dependency. + Being not a full-fledged C preprocessor, the scanner does not + expand the macro. + + + + + + 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. + + + + + + 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: + + + + + + + + #define FOO_HEADER <foo.h> + #include FOO_HEADER + + int main() { + return FOO; + } + + + obj = Object('hello.c', CCFLAGS='-MD -MF hello.d', CPPPATH='.') + SideEffect('hello.d', obj) + ParseDepends('hello.d') + Program('hello', obj) + + + #define FOO 42 + + + hello.o: hello.c foo.h + + + + + scons -Q + edit foo.h + scons -Q + + + + + Parsing dependencies from a compiler-generated + .d file has a chicken-and-egg problem, that + causes unnecessary rebuilds: + + + + + + #define FOO_HEADER <foo.h> + #include FOO_HEADER + + int main() { + return FOO; + } + + + obj = Object('hello.c', CCFLAGS='-MD -MF hello.d', CPPPATH='.') + SideEffect('hello.d', obj) + ParseDepends('hello.d') + Program('hello', obj) + + + #define FOO 42 + + + + + + + % scons -Q + cc -o hello.o -c -MD -MF hello.d -I. hello.c + cc -o hello hello.o + % scons -Q --debug=explain + scons: rebuilding `hello.o' because `foo.h' is a new dependency + cc -o hello.o -c -MD -MF hello.d -I. hello.c + % scons -Q + scons: `.' is up to date. + + + + + 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 foo.h. In the second pass, + the object file is regenerated because foo.h + is detected as a new dependency. + + + + + + &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. + + + +
+ +
+ Ignoring Dependencies: the &Ignore; Function + + + + 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: + + + + + + hello = Program('hello.c') + Ignore(hello, 'hello.h') + + + #include "hello.h" + int main() { printf("Hello, %s!\n", string); } + + + #define string "world" + + + + + + + + + % scons -Q hello + cc -c -o hello.o hello.c + cc -o hello hello.o + % scons -Q hello + scons: `hello' is up to date. + % edit hello.h + [CHANGE THE CONTENTS OF hello.h] + % scons -Q hello + scons: `hello' is up to date. + + + + + 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: + + + + + hello = Program('hello.c', CPPPATH=['/usr/include']) + Ignore(hello, '/usr/include/stdio.h') + + + + &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. + + + + + hello_obj=Object('hello.c') + hello = Program(hello_obj) + Ignore('.',[hello,hello_obj]) + + + #include "stdio.h" + int main() { printf("Hello!\n"); } + + + + + scons -Q + scons -Q hello + scons -Q hello + +
+ +
+ Order-Only Dependencies: the &Requires; Function + + + + 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 not + require that the target itself be rebuilt. + Such a relationship is called an + order-only dependency + 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. + + + + + + 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 version.c 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 version.c in the sources: + + + + + + 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']) + + + extern char *date; + int main() { printf("Hello, %s! I was built: %s\n", date); } + + + + + + If we list version.c as an actual source file, + though, then version.o + will get rebuilt every time we run &SCons; + (because the &SConstruct; file itself changes + the contents of version.c) + and the hello executable + will get re-linked every time + (because the version.o file changes): + + + + + + + % scons -Q + gcc -o hello.o -c hello.c + gcc -o version.o -c version.c + gcc -o hello hello.o version.o + % scons -Q + gcc -o version.o -c version.c + gcc -o hello hello.o version.o + % scons -Q + gcc -o version.o -c version.c + gcc -o hello hello.o version.o + + + + + One solution is to use the &Requires; function + to specify that the version.o + must be rebuilt before it is used by the link step, + but that changes to version.o + should not actually cause the hello + executable to be re-linked: + + + + + + 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) + + + extern char *date; + int main() { printf("Hello, %s! I was built: %s\n", date); } + + + + + + Notice that because we can no longer list version.c + as one of the sources for the hello 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 version_obj + 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. + + + + + + With these changes, + we get the desired behavior of + re-building the version.o file, + and therefore re-linking the hello executable, + only when the hello.c has changed: + + + + + scons -Q + scons -Q + edit hello.c + scons -Q + scons -Q + + +
+ +
+ The &AlwaysBuild; Function + + + + How &SCons; handles dependencies can also be affected + by the &AlwaysBuild; method. + When a file is passed to the &AlwaysBuild; method, + like so: + + + + + + hello = Program('hello.c') + AlwaysBuild(hello) + + + int main() { printf("Hello, %s!\n", string); } + + + + + + 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: + + + + + scons -Q + scons -Q + + + + + 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 not + itself depend on the &AlwaysBuild; target, + will still be rebuilt only if it's out-of-date + with respect to its dependencies: + + + + + scons -Q + scons -Q hello.o + + + + +
+ + -- cgit v1.2.3