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.
29 =head2 Repository dependency analysis
31 Due to its built-in scanning, Cons will search the specified repository
32 trees for included F<.h> files. Unless the compiler also knows about the
33 repository trees, though, it will be unable to find F<.h> files that only
34 exist in a repository. If, for example, the F<hello.c> file includes the
35 F<hello.h> file in its current directory:
37 % cons -R /usr/all/repository hello
38 gcc -c /usr/all/repository/hello.c -o hello.o
39 /usr/all/repository/hello.c:1: hello.h: No such file or directory
41 Solving this problem forces some requirements onto the way construction
42 environments are defined and onto the way the C C<#include> preprocessor
43 directive is used to include files.
45 In order to inform the compiler about the repository trees, Cons will add
46 appropriate C<-I> flags to the compilation commands. This means that the
47 C<CPPPATH> variable in the construction environment must explicitly specify
48 all subdirectories which are to be searched for included files, including the
49 current directory. Consequently, we can fix the above example by changing
50 the environment creation in the F<Construct> file as follows:
58 Due to the definition of the C<CPPPATH> variable, this yields, when we
59 re-execute the command:
61 % cons -R /usr/all/repository hello
62 gcc -c -I. -I/usr/all/repository /usr/all/repository/hello.c -o hello.o
63 gcc -o hello hello.o /usr/all/repository/libworld.a
65 The order of the C<-I> flags replicates, for the C preprocessor, the same
66 repository-directory search path that Cons uses for its own dependency
67 analysis. If there are multiple repositories and multiple C<CPPPATH>
68 directories, Cons will append the repository directories to the beginning of
69 each C<CPPPATH> directory, rapidly multiplying the number of C<-I> flags.
70 As an extreme example, a F<Construct> file containing:
81 Would yield a compilation command of:
83 cc -Ia -I/u1/a -I/u2/a -Ib -I/u1/b -I/u2/b -Ic -I/u1/c -I/u2/c -c hello.c -o hello.o
85 In order to shorten the command lines as much as possible, Cons will
86 remove C<-I> flags for any directories, locally or in the repositories,
87 which do not actually exist. (Note that the C<-I> flags are not included
88 in the MD5 signature calculation for the target file, so the target will
89 not be recompiled if the compilation command changes due to a directory
90 coming into existence.)
92 Because Cons relies on the compiler's C<-I> flags to communicate the
93 order in which repository directories must be searched, Cons' handling
94 of repository directories is fundamentally incompatible with using
95 double-quotes on the C<#include> directives in any C source code that
98 #include "file.h" /* DON'T USE DOUBLE-QUOTES LIKE THIS */
100 This is because most C preprocessors, when faced with such a directive, will
101 always first search the directory containing the source file. This
102 undermines the elaborate C<-I> options that Cons constructs to make the
103 preprocessor conform to its preferred search path.
105 Consequently, when using repository trees in Cons, B<always> use
106 angle-brackets for included files in any C source (.c or .h) files that
107 you plan to modify locally:
109 #include <file.h> /* USE ANGLE-BRACKETS INSTEAD */
111 Code that will not change can still safely use double quotes on #include
115 =head2 Repository_List
117 Cons provides a C<Repository_List> command to return a list of all
118 repository directories in their current search order. This can be used for
119 debugging, or to do more complex Perl stuff:
121 @list = Repository_List;
122 print join(' ', @list), "\n";
125 =head2 Repository interaction with other Cons features
127 Cons' handling of repository trees interacts correctly with other Cons
128 features, which is to say, it generally does what you would expect.
130 Most notably, repository trees interact correctly, and rather powerfully,
131 with the 'Link' command. A repository tree may contain one or more
132 subdirectories for version builds established via C<Link> to a source
133 subdirectory. Cons will search for derived files in the appropriate build
134 subdirectories under the repository tree.
140 Often, a software project will have
141 one or more central repositories,
142 directory trees that contain
143 source code, or derived files, or both.
144 You can eliminate additional unnecessary
145 rebuilds of files by having &SCons;
146 use files from one or more code repositories
147 to build files in your local build tree.
152 <title>The &Repository; Method</title>
156 The repository directories specified may contain source files, derived files
157 (objects, libraries and executables), or both. If there is no local file
158 (source or derived) under the directory in which Cons is executed, then the
159 first copy of a same-named file found under a repository directory will be
160 used to build any local derived files.
166 It's often useful to allow multiple programmers working
167 on a project to build software from
168 source files and/or derived files that
169 are stored in a centrally-accessible repository,
170 a directory copy of the source code tree.
171 (Note that this is not the sort of repository
172 maintained by a source code management system
173 like BitKeeper, CVS, or Subversion.
174 For information about using &SCons;
175 with these systems, see the section,
176 "Fetching Files From Source Code Management Systems,"
178 You use the &Repository; method
179 to tell &SCons; to search one or more
180 central code repositories (in order)
181 for any source files and derived files
182 that are not present in the local build tree:
186 <scons_example name="ex1">
187 <file name="SConstruct" printme="1">
189 env.Program('hello.c')
190 Repository('/usr/repository1', '/usr/repository2')
192 <file name="hello.c">
193 int main() { printf("Hello, world!\n"); }
199 Multiple calls to the &Repository; method
200 will simply add repositories to the global list
201 that &SCons; maintains,
202 with the exception that &SCons; will automatically eliminate
203 the current directory and any non-existent
204 directories from the list.
211 <title>Finding source files in repositories</title>
216 specifies that &SCons;
217 will first search for files under
218 the <filename>/usr/repository1</filename> tree
219 and next under the <filename>/usr/repository2</filename> tree.
220 &SCons; expects that any files it searches
221 for will be found in the same position
222 relative to the top-level directory.
223 In the above example, if the &hello_c; file is not
224 found in the local build tree,
225 &SCons; will search first for
226 a <filename>/usr/repository1/hello.c</filename> file
227 and then for a <filename>/usr/repository1/hello.c</filename> file
234 So given the &SConstruct; file above,
235 if the &hello_c; file exists in the local
237 &SCons; will rebuild the &hello; program
242 <scons_output example="ex1">
243 <command>scons -Q</command>
248 If, however, there is no local &hello_c; file,
249 but one exists in <filename>/usr/repository1</filename>,
250 &SCons; will recompile the &hello; program
251 from the source file it finds in the repository:
255 <scons_example name="ex2">
256 <file name="SConstruct">
258 env.Program('hello.c')
259 Repository('/usr/repository1', '/usr/repository2')
261 <file name="hello.c">
262 int main() { printf("Hello, world!\n"); }
266 <scons_output example="ex2">
267 <command>scons -Q</command>
268 gcc -c /usr/repository1/hello.c -o hello.o
274 And similarly, if there is no local &hello_c; file
275 and no <filename>/usr/repository1/hello.c</filename>,
276 but one exists in <filename>/usr/repository2</filename>:
280 <scons_example name="ex3">
281 <file name="SConstruct">
283 env.Program('hello.c')
284 Repository('/usr/repository1', '/usr/repository2')
286 <file name="hello.c">
287 int main() { printf("Hello, world!\n"); }
291 <scons_output example="ex3">
292 <command>scons -Q</command>
302 <title>Finding the &SConstruct; file in repositories</title>
306 &SCons; will also search in repositories
307 for the &SConstruct; file and any specified &SConscript; files.
308 This poses a problem, though: how can &SCons; search a
309 repository tree for an &SConstruct; file
310 if the &SConstruct; file itself contains the information
311 about the pathname of the repository?
312 To solve this problem, &SCons; allows you
313 to specify repository directories
314 on the command line using the <literal>-Y</literal> option:
319 % <userinput>scons -Q -Y /usr/repository1 -Y /usr/repository2</userinput>
324 When looking for source or derived files,
325 &SCons; will first search the repositories
326 specified on the command line,
327 and then search the repositories
328 specified in the &SConstruct; or &SConscript; files.
335 <title>Finding derived files in repositories</title>
339 If a repository contains not only source files,
340 but also derived files (such as object files,
341 libraries, or executables), &SCons; will perform
342 its normal MD5 signature calculation to
343 decide if a derived file in a repository is up-to-date,
344 or the derived file must be rebuilt in the local build directory.
345 For the &SCons; signature calculation to work correctly,
346 a repository tree must contain the &sconsign; files
347 that &SCons; uses to keep track of signature information.
353 Usually, this would be done by a build integrator
354 who would run &SCons; in the repository
355 to create all of its derived files and &sconsign; files,
356 or who would &SCons; in a separate build directory
357 and copying the resulting tree to the desired repository:
361 <scons_example name="ex4">
362 <file name="SConstruct">
364 env.Program(['hello.c', 'file1.c', 'file2.c'])
365 Repository('/usr/repository1', '/usr/repository2')
367 <file name="hello.c">
368 int main() { printf("Hello, world!\n"); }
370 <file name="file1.c">
371 int f1() { printf("file1\n"); }
373 <file name="file2.c">
374 int f2() { printf("file2.c\n"); }
378 <scons_output example="ex4">
379 <command>cd /usr/repository1</command>
380 <command>scons -Q</command>
385 (Note that this is safe even if the &SConstruct; file
386 lists <filename>/usr/repository1</filename> as a repository,
387 because &SCons; will remove the current build directory
388 from its repository list for that invocation.)
394 Now, with the repository populated,
395 we only need to create the one local source file
396 we're interested in working with at the moment,
397 and use the <literal>-Y</literal> option to
398 tell &SCons; to fetch any other files it needs
404 <scons_output example="ex4">
405 <command>cd $HOME/build</command>
406 <command>edit hello.c</command>
407 <command>scons -Q -Y __ROOT__/usr/repository1</command>
411 % <userinput>cd $HOME/build</userinput>
412 % <userinput>edit hello.c</userinput>
413 % <userinput>scons -Q -Y /usr/repository1</userinput>
414 cc -c -o hello.o hello.c
415 cc -o hello hello.o /usr/repository1/file1.o /usr/repository1/file2.o
420 Notice that &SCons; realizes that it does not need to
421 rebuild local copies file1.o and file2.o files,
422 but instead uses the already-compiled files
430 <title>Guaranteeing local copies of files</title>
434 If the repository tree contains the complete results of a build,
435 and we try to build from the repository
436 without any files in our local tree,
437 something moderately surprising happens:
442 % <userinput>mkdir $HOME/build2</userinput>
443 % <userinput>cd $HOME/build2</userinput>
444 % <userinput>scons -Q -Y /usr/all/repository hello</userinput>
445 scons: `hello' is up-to-date.
450 Why does &SCons; say that the &hello; program
451 is up-to-date when there is no &hello; program
452 in the local build directory?
453 Because the repository (not the local directory)
454 contains the up-to-date &hello; program,
455 and &SCons; correctly determines that nothing
456 needs to be done to rebuild that
457 up-to-date copy of the file.
463 There are, however, many times when you want to ensure that a
464 local copy of a file always exists.
465 A packaging or testing script, for example,
466 may assume that certain generated files exist locally.
467 To tell &SCons; to make a copy of any up-to-date repository
468 file in the local build directory,
469 use the &Local; function:
473 <scons_example name="ex5">
474 <file name="SConstruct" printme="1">
476 hello = env.Program('hello.c')
479 <file name="hello.c">
480 int main() { printf("Hello, world!\n"); }
486 If we then run the same command,
487 &SCons; will make a local copy of the program
488 from the repository copy,
489 and tell you that it is doing so:
494 % <userinput>scons -Y /usr/all/repository hello</userinput>
495 Local copy of hello from /usr/all/repository/hello
496 scons: `hello' is up-to-date.
501 (Notice that, because the act of making the local copy
502 is not considered a "build" of the &hello; file,
503 &SCons; still reports that it is up-to-date.)