3 Copyright (c) 2001, 2002, 2003 Steven Knight
5 Permission is hereby granted, free of charge, to any person obtaining
6 a copy of this software and associated documentation files (the
7 "Software"), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sublicense, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 =head2 The C<Salt> method
30 The C<Salt> method adds a constant value to the signature calculation
31 for every derived file. It is invoked as follows:
35 Changing the Salt value will force a complete rebuild of every derived
36 file. This can be used to force rebuilds in certain desired
37 circumstances. For example,
41 Would force a complete rebuild of every derived file whenever the
42 operating system on which the build is performed (as reported by C<uname
49 So far we've seen how &SCons; handles one-time builds.
50 But the real point of a build tool like &SCons;
51 is to rebuild only the necessary things
52 when source files change--or, put another way,
53 &SCons; should <emphasis>not</emphasis>
54 waste time rebuilding things that have already been built.
55 You can see this at work simply be re-invoking &SCons;
56 after building our simple &hello; example:
60 <scons_example name="ex1">
61 <file name="SConstruct">
63 env.Program('hello.c')
66 int main() { printf("Hello, world!\n"); }
70 <scons_output example="ex1" os="posix">
71 <command>scons</command>
72 <command>scons</command>
77 The second time it is executed,
78 &SCons; realizes that the &hello; program
79 is up-to-date with respect to the current &hello_c; source file,
80 and avoids rebuilding it.
81 You can see this more clearly by naming
82 the &hello; program explicitly on the command line:
86 <scons_output example="ex1" os="posix">
87 <command>scons hello</command>
88 <command>scons hello</command>
93 Note that &SCons; reports <literal>"...is up to date"</literal>
94 only for target files named explicitly on the command line,
95 to avoid cluttering the output.
100 <title>Source File Signatures</title>
104 The other side of avoiding unnecessary rebuilds
105 is the fundamental build tool behavior
106 of <emphasis>rebuilding</emphasis>
107 things when a source file changes,
108 so that the built software is up to date.
109 &SCons; keeps track of this through a
110 &signature; for each source file,
111 and allows you to configure
112 whether you want to use the source
113 file contents or the modification time (timestamp)
119 <title>MD5 Source File Signatures</title>
124 &SCons; keeps track of whether a source file has changed
125 based on the file's contents,
126 not the modification time.
127 This means that you may be surprised by the
128 default &SCons; behavior if you are used to the
129 &Make; convention of forcing
130 a rebuild by updating the file's modification time
131 (using the &touch; command, for example):
135 <scons_output example="ex1" os="posix">
136 <command>scons hello</command>
137 <command>touch hello.c</command>
138 <command>scons hello</command>
143 Even though the file's modification time has changed,
144 &SCons; realizes that the contents of the
145 &hello_c; file have <emphasis>not</emphasis> changed,
146 and therefore that the &hello; program
148 This avoids unnecessary rebuilds when,
149 for example, someone rewrites the
150 contents of a file without making a change.
151 But if the contents of the file really do change,
152 then &SCons; detects the change
153 and rebuilds the program as required:
157 <scons_output example="ex1" os="posix">
158 <command>scons hello</command>
159 <command output="[CHANGE THE CONTENTS OF hello.c]">edit hello.c</command>
160 <command>scons hello</command>
166 % <userinput>scons hello</userinput>
167 cc -c hello.c -o hello.o
169 % <userinput>edit hello.c</userinput>
170 [CHANGE THE CONTENTS OF hello.c]
171 % <userinput>scons hello</userinput>
172 cc -c hello.c -o hello.o
181 Note that you can, if you wish,
182 specify this default behavior
183 (MD5 signatures) explicitly
184 using the &SourceSignatures; function as follows:
190 env.Program('hello.c')
191 SourceSignatures('MD5')
197 <title>Source File Time Stamps</title>
201 If you prefer, you can
202 configure &SCons; to use the modification time
204 not the file contents,
205 when deciding if something needs to be rebuilt.
206 To do this, call the &SourceSignatures;
211 <scons_example name="ex2">
212 <file name="SConstruct" printme="1">
214 env.Program('hello.c')
215 SourceSignatures('timestamp')
217 <file name="hello.c">
218 int main() { printf("Hello, world!\n"); }
224 This makes &SCons; act like &Make;
225 when a file's modification time is updated
226 (using the &touch; command, for example):
230 <scons_output example="ex1" os="posix">
231 <command>scons hello</command>
232 <command>touch hello.c</command>
233 <command>scons hello</command>
241 <title>Target File Signatures</title>
246 &SCons; uses signatures to decide whether a
247 target file is up to date or must be rebuilt.
248 When a target file depends on another target file,
249 &SCons; allows you to separately configure
250 how the signatures of an "intermediate" target file
251 is used when deciding if a dependent target file
257 <title>Build Signatures</title>
261 Modifying a source file
262 will cause not only its direct target file to be rebuilt,
263 but also the target file(s)
264 that depend on that direct target file.
266 changing the contents of the &hello_c; file causes
267 the &hello_o; file to be rebuilt,
268 which in turn causes the
269 &hello; program to be rebuilt:
273 <scons_output example="ex1" os="posix">
274 <command>scons hello</command>
275 <command output="[CHANGE THE CONTENTS OF hello.c]">edit hello.c</command>
276 <command>scons hello</command>
282 % <userinput>scons hello</userinput>
283 cc -c hello.c -o hello.o
285 % <userinput>edit hello.c</userinput>
286 [CHANGE THE CONTENTS OF hello.c]
287 % <userinput>scons hello</userinput>
288 cc -c hello.c -o hello.o
297 What's not obvious, though,
298 is that &SCons; internally handles the signature of
300 (&hello_o; in the above example)
301 differently from the signature of the source file
304 &SCons; tracks whether a target file must be rebuilt
305 by using a &buildsignature;
306 that consists of the combined
307 signatures of all the files
308 that go into making the target file.
309 This is efficient because
310 the accumulated signatures
311 actually give &SCons; all of the
313 to decide if the target file is out of date.
320 specify this default behavior
321 (build signatures) explicitly
322 using the &TargetSignatures; function:
328 env.Program('hello.c')
329 TargetSignatures('build')
335 <title>File Contents</title>
339 Sometimes a source file can be changed
340 in such a way that the contents of the
341 rebuilt target file(s)
342 will be exactly the same as the last time
344 If so, then any other target files
345 that depend on such a built-but-not-changed target
346 file actually need not be rebuilt.
348 realize that a dependent target file
349 need not be rebuilt in this situation
350 using the &TargetSignatures; function as follows:
354 <scons_example name="ex3">
355 <file name="SConstruct" printme="1">
357 env.Program('hello.c')
358 TargetSignatures('content')
360 <file name="hello.c">
361 int main() { printf("Hello, world!\n"); }
368 a user were to only change a comment in a C file,
369 then the rebuilt &hello_o; file
370 would be exactly the same as the one previously built
371 (assuming the compiler doesn't put any build-specific
372 information in the object file).
373 &SCons; would then realize that it would not
374 need to rebuild the &hello; program as follows:
378 <scons_output example="ex3" os="posix">
379 <command>scons hello</command>
380 <command output="[CHANGE A COMMENT IN hello.c]">edit hello.c</command>
381 <command>scons hello</command>
386 In essence, &SCons; has
387 "short-circuited" any dependent builds
388 when it realizes that a target file
389 has been rebuilt to exactly the same file as the last build.
391 &SCons; does take some extra processing time
392 to scan the contents of the target (&hello_o;) file,
393 but this may save time
394 if the rebuild that was avoided
395 would have been very time-consuming and expensive.
404 <title>Implicit Dependencies: The &CPPPATH; Construction Variable</title>
408 Now suppose that our "Hello, World!" program
409 actually has a <literal>#include</literal> line
410 to include the &hello_h; file in the compilation:
414 <scons_example name="ex4">
415 <file name="SConstruct">
416 env = Environment(CPPPATH = '.')
417 hello = env.Program('hello.c')
419 <file name="hello.c" printme="1">
424 printf("Hello, %s!\n", string);
427 <file name="hello.h">
428 #define string "world"
434 And, for completeness, the &hello_h; file looks like this:
438 <scons_example_file example="ex4" name="hello.h">
439 </scons_example_file>
443 In this case, we want &SCons; to recognize that,
444 if the contents of the &hello_h; file change,
445 the &hello; program must be recompiled.
446 To do this, we need to modify the
447 &SConstruct; file like so:
451 <scons_example_file example="ex4" name="SConstruct">
452 </scons_example_file>
456 The &CPPPATH; assignment in the &Environment; call
457 tells &SCons; to look in the current directory
458 (<literal>'.'</literal>)
459 for any files included by C source files
460 (<filename>.c</filename> or <filename>.h</filename> files).
461 With this assignment in the &SConstruct; file:
465 <scons_output example="ex4" os="posix">
466 <command>scons hello</command>
467 <command>scons hello</command>
468 <command output="[CHANGE THE CONTENTS IN hello.h]">edit hello.h</command>
469 <command>scons hello</command>
474 First, notice that &SCons;
475 added the <literal>-I.</literal> argument
476 from the &CPPPATH; variable
477 so that the compilation would find the
478 &hello_h; file in the local directory.
484 Second, realize that &SCons; knows that the &hello;
485 program must be rebuilt
486 because it scans the contents of
488 for the <literal>#include</literal> lines that indicate
489 another file is being included in the compilation.
490 &SCons; records these as
491 <emphasis>implicit dependencies</emphasis>
494 when the &hello_h; file changes,
495 &SCons; realizes that the &hello_c; file includes it,
496 and rebuilds the resulting &hello; program
497 that depends on both the &hello_c; and &hello_h; files.
503 Like the &LIBPATH; variable,
504 the &CPPPATH; variable
505 may be a list of directories,
506 or a string separated by
507 the system-specific path separate character
508 (':' on POSIX/Linux, ';' on Windows).
509 Either way, &SCons; creates the
510 right command-line options
511 so that the following example:
518 <scons_example name="ex5">
519 <file name="SConstruct">
520 env = Environment(CPPPATH = ['include', '/home/project/inc'])
521 hello = env.Program('hello.c')
523 <file name="hello.c">
524 int main() { printf("Hello, world!\n"); }
530 Will look like this on POSIX or Linux:
534 <scons_output example="ex4" os="posix">
535 <command>scons hello</command>
540 And like this on Windows:
544 <scons_output example="ex4" os="win32">
545 <command>scons hello</command>
551 <title>Caching Implicit Dependencies</title>
555 Scanning each file for <literal>#include</literal> lines
556 does take some extra processing time.
557 When you're doing a full build of a large system,
558 the scanning time is usually a very small percentage
559 of the overall time spent on the build.
560 You're most likely to notice the scanning time,
561 however, when you <emphasis>rebuild</emphasis>
562 all or part of a large system:
563 &SCons; will likely take some extra time to "think about"
564 what must be built before it issues the
566 (or decides that everything is up to date
567 and nothing must be rebuilt).
570 Isn't this expensive? The answer is, it depends. If you do a full build of a
571 large system, the scanning time is insignificant. If you do a rebuild of a
572 large system, then Cons will spend a fair amount of time thinking about it
573 before it decides that nothing has to be done (although not necessarily more
574 time than make!). The good news is that Cons makes it very easy to
575 intelligently subset your build, when you are working on localized changes.
582 In practice, having &SCons; scan files saves time
583 relative to the amount of potential time
584 lost to tracking down subtle problems
585 introduced by incorrect dependencies.
586 Nevertheless, the "waiting time"
587 while &SCons; scans files can annoy
588 individual developers waiting for their builds to finish.
589 Consequently, &SCons; lets you cache
590 the implicit dependencies
591 that its scanners find,
592 for use by later builds.
593 You do this either by specifying the
594 &implicit-cache; option on the command line:
598 <scons_output example="ex1" os="win32">
599 <command>scons --implicit-cache hello</command>
600 <command>scons hello</command>
605 Or by setting the &implicit_cache; option
606 in an &SConscript; file:
611 SetOption('implicit_cache', 1)
616 &SCons; does not cache implicit dependencies like this by default
628 <title>The &implicit-deps-changed; Option</title>
639 <title>The &implicit-deps-unchanged; Option</title>
652 <title>The &Ignore; Method</title>
656 Sometimes it makes sense
657 to not rebuild a program,
658 even if a dependency file changes.
660 you would tell &SCons; specifically
661 to ignore a dependency as follows:
667 hello = env.Program('hello.c')
668 env.Ignore(hello, 'hello.h')
671 <!-- XXX mention that you can use arrays for target and source? -->
674 % <userinput>scons hello</userinput>
675 cc -c hello.c -o hello.o
677 % <userinput>scons hello</userinput>
678 scons: `hello' is up to date.
679 % <userinput>edit hello.h</userinput>
680 [CHANGE THE CONTENTS OF hello.h]
681 % <userinput>scons hello</userinput>
682 scons: `hello' is up to date.
687 Now, the above example is a little contrived,
688 because it's hard to imagine a real-world situation
689 where you wouldn't to rebuild &hello;
690 if the &hello_h; file changed.
691 A more realistic example
692 might be if the &hello;
693 program is being built in a
694 directory that is shared between multiple systems
695 that have different copies of the
696 &stdio_h; include file.
698 &SCons; would notice the differences between
699 the different systems' copies of &stdio_h;
700 and would rebuild &hello;
701 each time you change systems.
702 You could avoid these rebuilds as follows:
708 hello = env.Program('hello.c')
709 env.Ignore(hello, '/usr/include/stdio.h')
715 <title>The &Depends; Method</title>
720 sometimes a file depends on another file
721 that has no &SCons; scanner will detect.
723 &SCons; allows you to specific explicitly that one file
724 depends on another file,
725 and must be rebuilt whenever that file changes.
726 This is specified using the &Depends; method:
732 hello = env.Program('hello.c')
733 env.Depends(hello, 'other_file')
736 <!-- XXX mention that you can use arrays for target and source? -->
739 % <userinput>scons hello</userinput>
740 cc -c hello.c -o hello.o
742 % <userinput>scons hello</userinput>
743 scons: `hello' is up to date.
744 % <userinput>edit other_file</userinput>
745 [CHANGE THE CONTENTS OF other_file]
746 % <userinput>scons hello</userinput>
747 cc -c hello.c -o hello.o
756 <title>The &Salt; Method</title>