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 Often, a software project will have
29 one or more central repositories,
30 directory trees that contain
31 source code, or derived files, or both.
32 You can eliminate additional unnecessary
33 rebuilds of files by having &SCons;
34 use files from one or more code repositories
35 to build files in your local build tree.
40 <title>The &Repository; Method</title>
44 The repository directories specified may contain source files, derived files
45 (objects, libraries and executables), or both. If there is no local file
46 (source or derived) under the directory in which Cons is executed, then the
47 first copy of a same-named file found under a repository directory will be
48 used to build any local derived files.
54 It's often useful to allow multiple programmers working
55 on a project to build software from
56 source files and/or derived files that
57 are stored in a centrally-accessible repository,
58 a directory copy of the source code tree.
59 (Note that this is not the sort of repository
60 maintained by a source code management system
61 like BitKeeper, CVS, or Subversion.)
63 For information about using &SCons;
64 with these systems, see the section,
65 "Fetching Files From Source Code Management Systems,"
68 You use the &Repository; method
69 to tell &SCons; to search one or more
70 central code repositories (in order)
71 for any source files and derived files
72 that are not present in the local build tree:
76 <scons_example name="ex1">
77 <file name="SConstruct" printme="1">
79 env.Program('hello.c')
80 Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2')
83 int main() { printf("Hello, world!\n"); }
89 Multiple calls to the &Repository; method
90 will simply add repositories to the global list
91 that &SCons; maintains,
92 with the exception that &SCons; will automatically eliminate
93 the current directory and any non-existent
94 directories from the list.
101 <title>Finding source files in repositories</title>
106 specifies that &SCons;
107 will first search for files under
108 the <filename>/usr/repository1</filename> tree
109 and next under the <filename>/usr/repository2</filename> tree.
110 &SCons; expects that any files it searches
111 for will be found in the same position
112 relative to the top-level directory.
113 In the above example, if the &hello_c; file is not
114 found in the local build tree,
115 &SCons; will search first for
116 a <filename>/usr/repository1/hello.c</filename> file
117 and then for a <filename>/usr/repository2/hello.c</filename> file
124 So given the &SConstruct; file above,
125 if the &hello_c; file exists in the local
127 &SCons; will rebuild the &hello; program
132 <scons_output example="ex1">
133 <scons_output_command>scons -Q</scons_output_command>
138 If, however, there is no local &hello_c; file,
139 but one exists in <filename>/usr/repository1</filename>,
140 &SCons; will recompile the &hello; program
141 from the source file it finds in the repository:
145 <scons_example name="ex2">
146 <file name="SConstruct">
148 env.Program('hello.c')
149 Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2')
151 <file name="__ROOT__/usr/repository1/hello.c">
152 int main() { printf("Hello, world!\n"); }
156 <scons_output example="ex2">
157 <scons_output_command>scons -Q</scons_output_command>
162 And similarly, if there is no local &hello_c; file
163 and no <filename>/usr/repository1/hello.c</filename>,
164 but one exists in <filename>/usr/repository2</filename>:
168 <scons_example name="ex3">
169 <file name="SConstruct">
171 env.Program('hello.c')
172 Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2')
174 <file name="__ROOT__/usr/repository2/hello.c">
175 int main() { printf("Hello, world!\n"); }
179 <scons_output example="ex3">
180 <scons_output_command>scons -Q</scons_output_command>
190 <title>Finding <literal>#include</literal> files in repositories</title>
194 We've already seen that SCons will scan the contents of
195 a source file for <literal>#include</literal> file names
196 and realize that targets built from that source file
197 also depend on the <literal>#include</literal> file(s).
198 For each directory in the &cv-link-CPPPATH; list,
199 &SCons; will actually search the corresponding directories
200 in any repository trees and establish the
201 correct dependencies on any
202 <literal>#include</literal> files that it finds
203 in repository directory.
209 Unless the C compiler also knows about these directories
210 in the repository trees, though,
211 it will be unable to find the <literal>#include</literal> files.
212 If, for example, the &hello_c; file in
213 our previous example includes the &hello.h;
214 in its current directory,
215 and the &hello.h; only exists in the repository:
220 % <userinput>scons -Q</userinput>
221 cc -o hello.o -c hello.c
222 hello.c:1: hello.h: No such file or directory
227 In order to inform the C compiler about the repositories,
228 &SCons; will add appropriate
229 <literal>-I</literal> flags to the compilation commands
230 for each directory in the &cv-CPPPATH; list.
231 So if we add the current directory to the
232 construction environment &cv-CPPPATH; like so:
236 <scons_example name="CPPPATH">
237 <file name="SConstruct" printme="1">
238 env = Environment(CPPPATH = ['.'])
239 env.Program('hello.c')
240 Repository('__ROOT__/usr/repository1')
242 <file name="hello.c">
243 int main() { printf("Hello, world!\n"); }
249 Then re-executing &SCons; yields:
253 <scons_output example="CPPPATH">
254 <scons_output_command>scons -Q</scons_output_command>
259 The order of the <literal>-I</literal> options replicates,
260 for the C preprocessor,
261 the same repository-directory search path
262 that &SCons; uses for its own dependency analysis.
263 If there are multiple repositories and multiple &cv-CPPPATH;
264 directories, &SCons; will add the repository directories
265 to the beginning of each &cv-CPPPATH; directory,
266 rapidly multiplying the number of <literal>-I</literal> flags.
267 If, for example, the &cv-CPPPATH; contains three directories
268 (and shorter repository path names!):
272 <scons_example name="CPPPATH3">
273 <file name="SConstruct" printme="1">
274 env = Environment(CPPPATH = ['dir1', 'dir2', 'dir3'])
275 env.Program('hello.c')
276 Repository('__ROOT__/r1', '__ROOT__/r2')
278 <file name="hello.c">
279 int main() { printf("Hello, world!\n"); }
285 Then we'll end up with nine <literal>-I</literal> options
287 three (for each of the &cv-CPPPATH; directories)
288 times three (for the local directory plus the two repositories):
292 <scons_output example="CPPPATH3">
293 <scons_output_command>scons -Q</scons_output_command>
298 Cons classic did the following, does SCons?
300 In order to shorten the command lines as much as possible, Cons will
301 remove C<-I> flags for any directories, locally or in the repositories,
302 which do not actually exist. (Note that the C<-I> flags are not included
303 in the MD5 signature calculation for the target file, so the target will
304 not be recompiled if the compilation command changes due to a directory
305 coming into existence.)
310 <title>Limitations on <literal>#include</literal> files in repositories</title>
314 &SCons; relies on the C compiler's
315 <literal>-I</literal> options to control the order in which
316 the preprocessor will search the repository directories
317 for <literal>#include</literal> files.
318 This causes a problem, however, with how the C preprocessor
319 handles <literal>#include</literal> lines with
320 the file name included in double-quotes.
327 &SCons; will compile the &hello_c; file from
328 the repository if it doesn't exist in
330 If, however, the &hello_c; file in the repository contains
331 a <literal>#include</literal> line with the file name in
339 main(int argc, char *argv[])
341 printf(HELLO_MESSAGE);
348 Then the C preprocessor will <emphasis>always</emphasis>
349 use a &hello_h; file from the repository directory first,
350 even if there is a &hello_h; file in the local directory,
351 despite the fact that the command line specifies
352 <literal>-I</literal> as the first option:
356 <scons_example name="quote1">
357 <file name="SConstruct">
358 env = Environment(CPPPATH = ['.'])
359 env.Program('hello.c')
360 Repository('__ROOT__/usr/repository1')
362 <file name="__ROOT__/usr/repository1/hello.c">
363 int main() { printf("Hello, world!\n"); }
367 <scons_output example="quote1">
368 <scons_output_command>scons -Q</scons_output_command>
373 This behavior of the C preprocessor--always search
374 for a <literal>#include</literal> file in double-quotes
375 first in the same directory as the source file,
376 and only then search the <literal>-I</literal>--can
377 not, in general, be changed.
378 In other words, it's a limitation
379 that must be lived with if you want to use
380 code repositories in this way.
381 There are three ways you can possibly
382 work around this C preprocessor behavior:
391 Some modern versions of C compilers do have an option
392 to disable or control this behavior.
393 If so, add that option to &cv-link-CFLAGS;
394 (or &cv-link-CXXFLAGS; or both) in your construction environment(s).
395 Make sure the option is used for all construction
396 environments that use C preprocessing!
404 Change all occurrences of <literal>#include "file.h"</literal>
405 to <literal>#include &lt;file.h&gt;</literal>.
406 Use of <literal>#include</literal> with angle brackets
407 does not have the same behavior--the <literal>-I</literal>
408 directories are searched first
409 for <literal>#include</literal> files--which
410 gives &SCons; direct control over the list of
411 directories the C preprocessor will search.
419 Require that everyone working with compilation from
420 repositories check out and work on entire directories of files,
421 not individual files.
422 (If you use local wrapper scripts around
423 your source code control system's command,
424 you could add logic to enforce this restriction there.
436 <title>Finding the &SConstruct; file in repositories</title>
440 &SCons; will also search in repositories
441 for the &SConstruct; file and any specified &SConscript; files.
442 This poses a problem, though: how can &SCons; search a
443 repository tree for an &SConstruct; file
444 if the &SConstruct; file itself contains the information
445 about the pathname of the repository?
446 To solve this problem, &SCons; allows you
447 to specify repository directories
448 on the command line using the <literal>-Y</literal> option:
453 % <userinput>scons -Q -Y /usr/repository1 -Y /usr/repository2</userinput>
458 When looking for source or derived files,
459 &SCons; will first search the repositories
460 specified on the command line,
461 and then search the repositories
462 specified in the &SConstruct; or &SConscript; files.
469 <title>Finding derived files in repositories</title>
473 If a repository contains not only source files,
474 but also derived files (such as object files,
475 libraries, or executables), &SCons; will perform
476 its normal MD5 signature calculation to
477 decide if a derived file in a repository is up-to-date,
478 or the derived file must be rebuilt in the local build directory.
479 For the &SCons; signature calculation to work correctly,
480 a repository tree must contain the &sconsign; files
481 that &SCons; uses to keep track of signature information.
487 Usually, this would be done by a build integrator
488 who would run &SCons; in the repository
489 to create all of its derived files and &sconsign; files,
490 or who would run &SCons; in a separate build directory
491 and copy the resulting tree to the desired repository:
495 <scons_example name="ex4">
496 <file name="SConstruct">
498 env.Program(['hello.c', 'file1.c', 'file2.c'])
499 Repository('/usr/repository1', '/usr/repository2')
501 <file name="hello.c">
502 int main() { printf("Hello, world!\n"); }
504 <file name="file1.c">
505 int f1() { printf("file1\n"); }
507 <file name="file2.c">
508 int f2() { printf("file2.c\n"); }
512 <scons_output example="ex4">
513 <scons_output_command>cd /usr/repository1</scons_output_command>
514 <scons_output_command>scons -Q</scons_output_command>
519 (Note that this is safe even if the &SConstruct; file
520 lists <filename>/usr/repository1</filename> as a repository,
521 because &SCons; will remove the current build directory
522 from its repository list for that invocation.)
528 Now, with the repository populated,
529 we only need to create the one local source file
530 we're interested in working with at the moment,
531 and use the <literal>-Y</literal> option to
532 tell &SCons; to fetch any other files it needs
538 <scons_output example="ex4">
539 <scons_output_command>cd $HOME/build</scons_output_command>
540 <scons_output_command>edit hello.c</scons_output_command>
541 <scons_output_command>scons -Q -Y __ROOT__/usr/repository1</scons_output_command>
545 % <userinput>cd $HOME/build</userinput>
546 % <userinput>edit hello.c</userinput>
547 % <userinput>scons -Q -Y /usr/repository1</userinput>
548 cc -c -o hello.o hello.c
549 cc -o hello hello.o /usr/repository1/file1.o /usr/repository1/file2.o
554 Notice that &SCons; realizes that it does not need to
555 rebuild local copies <filename>file1.o</filename> and <filename>file2.o</filename> files,
556 but instead uses the already-compiled files
564 <title>Guaranteeing local copies of files</title>
568 If the repository tree contains the complete results of a build,
569 and we try to build from the repository
570 without any files in our local tree,
571 something moderately surprising happens:
576 % <userinput>mkdir $HOME/build2</userinput>
577 % <userinput>cd $HOME/build2</userinput>
578 % <userinput>scons -Q -Y /usr/all/repository hello</userinput>
579 scons: `hello' is up-to-date.
584 Why does &SCons; say that the &hello; program
585 is up-to-date when there is no &hello; program
586 in the local build directory?
587 Because the repository (not the local directory)
588 contains the up-to-date &hello; program,
589 and &SCons; correctly determines that nothing
590 needs to be done to rebuild that
591 up-to-date copy of the file.
597 There are, however, many times when you want to ensure that a
598 local copy of a file always exists.
599 A packaging or testing script, for example,
600 may assume that certain generated files exist locally.
601 To tell &SCons; to make a copy of any up-to-date repository
602 file in the local build directory,
603 use the &Local; function:
607 <scons_example name="ex5">
608 <file name="SConstruct" printme="1">
610 hello = env.Program('hello.c')
613 <file name="hello.c">
614 int main() { printf("Hello, world!\n"); }
620 If we then run the same command,
621 &SCons; will make a local copy of the program
622 from the repository copy,
623 and tell you that it is doing so:
628 % <userinput>scons -Y /usr/all/repository hello</userinput>
629 Local copy of hello from /usr/all/repository/hello
630 scons: `hello' is up-to-date.
635 (Notice that, because the act of making the local copy
636 is not considered a "build" of the &hello; file,
637 &SCons; still reports that it is up-to-date.)