79d9a7581b7e2721c3f86cd52c217f176b17d462
[scons.git] / doc / user / repositories.in
1 <!--
2
3   __COPYRIGHT__
4
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:
12
13   The above copyright notice and this permission notice shall be included
14   in all copies or substantial portions of the Software.
15
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.
23
24 -->
25
26 <!--
27
28
29 =head2 Repository dependency analysis
30
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:
36
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
40
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.
44
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:
51
52   $env = new cons(
53         CC      => 'gcc',
54         CPPPATH => '.',
55         LIBS    => 'libworld.a',
56   );
57
58 Due to the definition of the C<CPPPATH> variable, this yields, when we
59 re-execute the command:
60
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
64
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:
71
72   Repository qw(
73         /u1
74         /u2
75   );
76
77   $env = new cons(
78         CPPPATH => 'a:b:c',
79   );
80
81 Would yield a compilation command of:
82
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
84
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.)
91
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
96 you plan to modify:
97
98   #include "file.h"     /* DON'T USE DOUBLE-QUOTES LIKE THIS */
99
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.
104
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:
108
109   #include <file.h>     /* USE ANGLE-BRACKETS INSTEAD */
110
111 Code that will not change can still safely use double quotes on #include
112 lines.
113
114
115 =head2 Repository_List
116
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:
120
121   @list = Repository_List;
122   print join(' ', @list), "\n";
123
124
125 =head2 Repository interaction with other Cons features
126
127 Cons' handling of repository trees interacts correctly with other Cons
128 features, which is to say, it generally does what you would expect.
129
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.
135
136 -->
137
138   <para>
139
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.
148
149   </para>
150
151   <section>
152   <title>The &Repository; Method</title>
153
154  <!--
155
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.
161
162  -->
163
164     <para>
165
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,"
177     below.)
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:
183
184     </para>
185
186     <scons_example name="ex1">
187       <file name="SConstruct" printme="1">
188        env = Environment()
189        env.Program('hello.c')
190        Repository('/usr/repository1', '/usr/repository2')
191       </file>
192       <file name="hello.c">
193       int main() { printf("Hello, world!\n"); }
194       </file>
195     </scons_example>
196
197     <para>
198
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.
205
206     </para>
207
208   </section>
209
210   <section>
211   <title>Finding source files in repositories</title>
212
213     <para>
214
215     The above example
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
228     to use in its place.
229
230     </para>
231
232     <para>
233
234     So given the &SConstruct; file above,
235     if the &hello_c; file exists in the local
236     build directory,
237     &SCons; will rebuild the &hello; program
238     as normal:
239
240     </para>
241
242     <scons_output example="ex1">
243       <command>scons -Q</command>
244     </scons_output>
245
246     <para>
247
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:
252
253     </para>
254
255     <scons_example name="ex2">
256       <file name="SConstruct">
257        env = Environment()
258        env.Program('hello.c')
259        Repository('/usr/repository1', '/usr/repository2')
260       </file>
261       <file name="hello.c">
262       int main() { printf("Hello, world!\n"); }
263       </file>
264     </scons_example>
265
266     <scons_output example="ex2">
267       <command>scons -Q</command>
268       gcc -c /usr/repository1/hello.c -o hello.o
269       gcc -o hello hello.o
270     </scons_output>
271
272     <para>
273
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>:
277
278     </para>
279
280     <scons_example name="ex3">
281       <file name="SConstruct">
282        env = Environment()
283        env.Program('hello.c')
284        Repository('/usr/repository1', '/usr/repository2')
285       </file>
286       <file name="hello.c">
287       int main() { printf("Hello, world!\n"); }
288       </file>
289     </scons_example>
290
291     <scons_output example="ex3">
292       <command>scons -Q</command>
293     </scons_output>
294
295     <para>
296
297     </para>
298
299   </section>
300
301   <section>
302   <title>Finding the &SConstruct; file in repositories</title>
303
304     <para>
305
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:
315
316     </para>
317
318     <screen>
319       % <userinput>scons -Q -Y /usr/repository1 -Y /usr/repository2</userinput>
320     </screen>
321
322     <para>
323
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.
329
330     </para>
331
332   </section>
333
334   <section>
335   <title>Finding derived files in repositories</title>
336
337     <para>
338
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.
348
349     </para>
350
351     <para>
352
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:
358
359     </para>
360
361     <scons_example name="ex4">
362       <file name="SConstruct">
363        env = Environment()
364        env.Program(['hello.c', 'file1.c', 'file2.c'])
365        Repository('/usr/repository1', '/usr/repository2')
366       </file>
367       <file name="hello.c">
368       int main() { printf("Hello, world!\n"); }
369       </file>
370       <file name="file1.c">
371       int f1() { printf("file1\n"); }
372       </file>
373       <file name="file2.c">
374       int f2() { printf("file2.c\n"); }
375       </file>
376     </scons_example>
377
378     <scons_output example="ex4">
379       <command>cd /usr/repository1</command>
380       <command>scons -Q</command>
381     </scons_output>
382
383     <para>
384     
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.)
389
390     </para>
391
392     <para>
393
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
399     from the repository:
400
401     </para>
402
403     <!--
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>
408     </scons_output>
409     -->
410     <screen>
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
416     </screen>
417
418     <para>
419
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
423     from the repository.
424
425     </para>
426
427   </section>
428
429   <section>
430   <title>Guaranteeing local copies of files</title>
431
432     <para>
433
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:
438
439     </para>
440
441     <screen>
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.
446     </screen>
447
448     <para>
449
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.
458
459     </para>
460
461     <para>
462
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:
470
471     </para>
472
473     <scons_example name="ex5">
474       <file name="SConstruct" printme="1">
475        env = Environment()
476        hello = env.Program('hello.c')
477        Local(hello)
478       </file>
479       <file name="hello.c">
480       int main() { printf("Hello, world!\n"); }
481       </file>
482     </scons_example>
483
484     <para>
485
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:
490
491     </para>
492
493     <screen>
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.
497     </screen>
498
499     <para>
500
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.)
504
505     </para>
506
507   </section>