From 140d836e9cd54fb67b969fd82ef7ed19ba574d40 Mon Sep 17 00:00:00 2001 From: Luca Falavigna Date: Sat, 26 Apr 2014 15:11:58 +0200 Subject: Imported Upstream version 2.3.1 --- doc/user/depends.in | 1872 --------------------------------------------------- 1 file changed, 1872 deletions(-) delete mode 100644 doc/user/depends.in (limited to 'doc/user/depends.in') diff --git a/doc/user/depends.in b/doc/user/depends.in deleted file mode 100644 index de2e11c..0000000 --- a/doc/user/depends.in +++ /dev/null @@ -1,1872 +0,0 @@ - - - - - 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: - - - - - - Object('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.o - touch hello.c - scons -Q hello.o - - - - - 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: - - - - - Object('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: - - - - - - Object('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.o - touch -t 198901010000 hello.c - scons -Q hello.o - - - - - 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 be 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. - - - - - - Another thing to look out for is the fact that the three - attributes above may not be present at the time of the first run. - Without any prior build, no targets have been created and no - .sconsign DB file exists yet. - So, you should always check whether the - prev_ni attribute in question is available. - - - - - - We finally present a small example for a - csig-based decider function. Note how the - signature information for the dependency file - has to get initialized via get_csig - during each function call (this is mandatory!). - - - - - env = Environment() - - def config_file_decider(dependency, target, prev_ni): - import os.path - - # We always have to init the .csig value... - dep_csig = dependency.get_csig() - # .csig may not exist, because no target was built yet... - if 'csig' not in dir(prev_ni): - return True - # Target file may not exist yet - if not os.path.exists(str(target.abspath)): - return True - if dep_csig != prev_ni.csig: - # Some change on source file => update installed one - return True - return False - - def update_file(): - f = open("test.txt","a") - f.write("some line\n") - f.close() - - update_file() - - # Activate our own decider function - env.Decider(config_file_decider) - - env.Install("install","test.txt") - - -
- -
- 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. - These functions have been officially deprecated - as &SCons; version 2.0, - and their use is discouraged, - mainly because they rely on a somewhat - confusing distinction between how - source files and target files are handled. - These functions are documented here mainly in case you - encounter them in older &SConscript; files. - - - -
- 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_obj=Object('hello.c') - hello = Program(hello_obj) - Ignore(hello_obj, '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 the version.o file - 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 hello - sleep 1 - scons -Q hello - sleep 1 - scons -Q hello - - - - - (Note that for the above example to work, - we &sleep; for one second in between each run, - so that the &SConstruct; file will create a - version.c file with a time string - that's one second later than the previous run.) - - - - - - 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 only - re-linking the hello executable - when the hello.c has changed, - even though the version.o is rebuilt - (because the &SConstruct; file still changes the - version.c contents directly each run): - - - - - scons -Q hello - sleep 1 - scons -Q hello - sleep 1 - edit hello.c - scons -Q hello - sleep 1 - scons -Q hello - - -
- -
- 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