f22611b4ceba26e45b12cf2990debca78bb1f096
[scons.git] / doc / user / repositories.xml
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   <para>
27
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.
36
37   </para>
38
39   <section>
40   <title>The &Repository; Method</title>
41
42  <!--
43
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.
49
50  -->
51
52     <para>
53
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.)
62     <!--
63     For information about using &SCons;
64     with these systems, see the section,
65     "Fetching Files From Source Code Management Systems,"
66     below.)
67     -->
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:
73
74     </para>
75
76     <programlisting>
77        env = Environment()
78        env.Program('hello.c')
79        Repository('/usr/repository1', '/usr/repository2')
80     </programlisting>
81
82     <para>
83
84     Multiple calls to the &Repository; method
85     will simply add repositories to the global list
86     that &SCons; maintains,
87     with the exception that &SCons; will automatically eliminate
88     the current directory and any non-existent
89     directories from the list.
90
91     </para>
92
93   </section>
94
95   <section>
96   <title>Finding source files in repositories</title>
97
98     <para>
99
100     The above example
101     specifies that &SCons;
102     will first search for files under
103     the <filename>/usr/repository1</filename> tree
104     and next under the <filename>/usr/repository2</filename> tree.
105     &SCons; expects that any files it searches
106     for will be found in the same position
107     relative to the top-level directory.
108     In the above example, if the &hello_c; file is not
109     found in the local build tree,
110     &SCons; will search first for
111     a <filename>/usr/repository1/hello.c</filename> file
112     and then for a <filename>/usr/repository2/hello.c</filename> file
113     to use in its place.
114
115     </para>
116
117     <para>
118
119     So given the &SConstruct; file above,
120     if the &hello_c; file exists in the local
121     build directory,
122     &SCons; will rebuild the &hello; program
123     as normal:
124
125     </para>
126
127     <screen>
128       % <userinput>scons -Q</userinput>
129       cc -o hello.o -c hello.c
130       cc -o hello hello.o
131     </screen>
132
133     <para>
134
135     If, however, there is no local &hello_c; file,
136     but one exists in <filename>/usr/repository1</filename>,
137     &SCons; will recompile the &hello; program
138     from the source file it finds in the repository:
139
140     </para>
141
142     
143
144     <screen>
145       % <userinput>scons -Q</userinput>
146       cc -o hello.o -c /usr/repository1/hello.c
147       cc -o hello hello.o
148     </screen>
149
150     <para>
151
152     And similarly, if there is no local &hello_c; file
153     and no <filename>/usr/repository1/hello.c</filename>,
154     but one exists in <filename>/usr/repository2</filename>:
155
156     </para>
157
158     
159
160     <screen>
161       % <userinput>scons -Q</userinput>
162       cc -o hello.o -c /usr/repository2/hello.c
163       cc -o hello hello.o
164     </screen>
165
166     <para>
167
168     </para>
169
170   </section>
171
172   <section>
173   <title>Finding <literal>#include</literal> files in repositories</title>
174
175     <para>
176
177     We've already seen that SCons will scan the contents of
178     a source file for <literal>#include</literal> file names
179     and realize that targets built from that source file
180     also depend on the <literal>#include</literal> file(s).
181     For each directory in the &cv-link-CPPPATH; list,
182     &SCons; will actually search the corresponding directories
183     in any repository trees and establish the
184     correct dependencies on any
185     <literal>#include</literal> files that it finds
186     in repository directory.
187
188     </para>
189
190     <para>
191
192     Unless the C compiler also knows about these directories
193     in the repository trees, though,
194     it will be unable to find the <literal>#include</literal> files.
195     If, for example, the &hello_c; file in
196     our previous example includes the &hello;.h;
197     in its current directory,
198     and the &hello;.h; only exists in the repository:
199
200     </para>
201
202     <screen>
203       % <userinput>scons -Q</userinput>
204       cc -o hello.o -c hello.c
205       hello.c:1: hello.h: No such file or directory
206     </screen>
207
208     <para>
209
210     In order to inform the C compiler about the repositories,
211     &SCons; will add appropriate
212     <literal>-I</literal> flags to the compilation commands
213     for each directory in the &cv-CPPPATH; list.
214     So if we add the current directory to the
215     construction environment &cv-CPPPATH; like so:
216
217     </para>
218
219     <programlisting>
220        env = Environment(CPPPATH = ['.'])
221        env.Program('hello.c')
222        Repository('/usr/repository1')
223     </programlisting>
224
225     <para>
226
227     Then re-executing &SCons; yields:
228
229     </para>
230
231     <screen>
232       % <userinput>scons -Q</userinput>
233       cc -o hello.o -c -I. -I/usr/repository1 hello.c
234       cc -o hello hello.o
235     </screen>
236
237     <para>
238
239     The order of the <literal>-I</literal> options replicates,
240     for the C preprocessor,
241     the same repository-directory search path
242     that &SCons; uses for its own dependency analysis.
243     If there are multiple repositories and multiple &cv-CPPPATH;
244     directories, &SCons; will add the repository directories
245     to the beginning of each &cv-CPPPATH; directory,
246     rapidly multiplying the number of <literal>-I</literal> flags.
247     If, for example, the &cv-CPPPATH; contains three directories
248     (and shorter repository path names!):
249
250     </para>
251
252     <programlisting>
253        env = Environment(CPPPATH = ['dir1', 'dir2', 'dir3'])
254        env.Program('hello.c')
255        Repository('/r1', '/r2')
256     </programlisting>
257
258     <para>
259
260     Then we'll end up with nine <literal>-I</literal> options
261     on the command line,
262     three (for each of the &cv-CPPPATH; directories)
263     times three (for the local directory plus the two repositories):
264
265     </para>
266
267     <screen>
268       % <userinput>scons -Q</userinput>
269       cc -o hello.o -c -Idir1 -I/r1/dir1 -I/r2/dir1 -Idir2 -I/r1/dir2 -I/r2/dir2 -Idir3 -I/r1/dir3 -I/r2/dir3 hello.c
270       cc -o hello hello.o
271     </screen>
272
273 <!--
274
275 Cons classic did the following, does SCons?
276
277 In order to shorten the command lines as much as possible, Cons will
278 remove C<-I> flags for any directories, locally or in the repositories,
279 which do not actually exist.  (Note that the C<-I> flags are not included
280 in the MD5 signature calculation for the target file, so the target will
281 not be recompiled if the compilation command changes due to a directory
282 coming into existence.)
283
284 -->
285
286     <section>
287     <title>Limitations on <literal>#include</literal> files in repositories</title>
288
289       <para>
290
291       &SCons; relies on the C compiler's
292       <literal>-I</literal> options to control the order in which
293       the preprocessor will search the repository directories
294       for <literal>#include</literal> files.
295       This causes a problem, however, with how the C preprocessor
296       handles <literal>#include</literal> lines with
297       the file name included in double-quotes.
298
299       </para>
300
301       <para>
302
303       As we've seen,
304       &SCons; will compile the &hello_c; file from
305       the repository if it doesn't exist in
306       the local directory.
307       If, however, the &hello_c; file in the repository contains
308       a <literal>#include</literal> line with the file name in
309       double quotes:
310
311       </para>
312
313       <programlisting>
314         #include "hello.h"
315         int
316         main(int argc, char *argv[])
317         {
318             printf(HELLO_MESSAGE);
319             return (0);
320         }
321       </programlisting>
322
323       <para>
324
325       Then the C preprocessor will <emphasis>always</emphasis>
326       use a &hello_h; file from the repository directory first,
327       even if there is a &hello_h; file in the local directory,
328       despite the fact that the command line specifies
329       <literal>-I</literal> as the first option:
330
331       </para>
332
333       
334
335       <screen>
336         % <userinput>scons -Q</userinput>
337         cc -o hello.o -c -I. -I/usr/repository1 /usr/repository1/hello.c
338         cc -o hello hello.o
339       </screen>
340
341       <para>
342
343       This behavior of the C preprocessor--always search
344       for a <literal>#include</literal> file in double-quotes
345       first in the same directory as the source file,
346       and only then search the <literal>-I</literal>--can
347       not, in general, be changed.
348       In other words, it's a limitation
349       that must be lived with if you want to use
350       code repositories in this way.
351       There are three ways you can possibly
352       work around this C preprocessor behavior:
353
354       </para>
355
356       <orderedlist>
357
358         <listitem>
359         <para>
360
361         Some modern versions of C compilers do have an option
362         to disable or control this behavior.
363         If so, add that option to &cv-link-CFLAGS;
364         (or &cv-link-CXXFLAGS; or both) in your construction environment(s).
365         Make sure the option is used for all construction
366         environments that use C preprocessing!
367
368         </para>
369         </listitem>
370
371         <listitem>
372         <para>
373
374         Change all occurrences of <literal>#include "file.h"</literal>
375         to <literal>#include &lt;file.h&gt;</literal>.
376         Use of <literal>#include</literal> with angle brackets
377         does not have the same behavior--the <literal>-I</literal>
378         directories are searched first
379         for <literal>#include</literal> files--which
380         gives &SCons; direct control over the list of
381         directories the C preprocessor will search.
382
383         </para>
384         </listitem>
385
386         <listitem>
387         <para>
388
389         Require that everyone working with compilation from
390         repositories check out and work on entire directories of files,
391         not individual files.
392         (If you use local wrapper scripts around
393         your source code control system's command,
394         you could add logic to enforce this restriction there.
395
396         </para>
397         </listitem>
398
399       </orderedlist>
400
401     </section>
402
403   </section>
404
405   <section>
406   <title>Finding the &SConstruct; file in repositories</title>
407
408     <para>
409
410     &SCons; will also search in repositories
411     for the &SConstruct; file and any specified &SConscript; files.
412     This poses a problem, though:  how can &SCons; search a
413     repository tree for an &SConstruct; file
414     if the &SConstruct; file itself contains the information
415     about the pathname of the repository?
416     To solve this problem, &SCons; allows you
417     to specify repository directories
418     on the command line using the <literal>-Y</literal> option:
419
420     </para>
421
422     <screen>
423       % <userinput>scons -Q -Y /usr/repository1 -Y /usr/repository2</userinput>
424     </screen>
425
426     <para>
427
428     When looking for source or derived files,
429     &SCons; will first search the repositories
430     specified on the command line,
431     and then search the repositories
432     specified in the &SConstruct; or &SConscript; files.
433
434     </para>
435
436   </section>
437
438   <section>
439   <title>Finding derived files in repositories</title>
440
441     <para>
442
443     If a repository contains not only source files,
444     but also derived files (such as object files,
445     libraries, or executables), &SCons; will perform
446     its normal MD5 signature calculation to
447     decide if a derived file in a repository is up-to-date,
448     or the derived file must be rebuilt in the local build directory.
449     For the &SCons; signature calculation to work correctly,
450     a repository tree must contain the &sconsign; files
451     that &SCons; uses to keep track of signature information.
452
453     </para>
454
455     <para>
456
457     Usually, this would be done by a build integrator
458     who would run &SCons; in the repository
459     to create all of its derived files and &sconsign; files,
460     or who would &SCons; in a separate build directory
461     and copying the resulting tree to the desired repository:
462
463     </para>
464
465     
466
467     <screen>
468       % <userinput>cd /usr/repository1</userinput>
469       % <userinput>scons -Q</userinput>
470       cc -o file1.o -c file1.c
471       cc -o file2.o -c file2.c
472       cc -o hello.o -c hello.c
473       cc -o hello hello.o file1.o file2.o
474     </screen>
475
476     <para>
477     
478     (Note that this is safe even if the &SConstruct; file
479     lists <filename>/usr/repository1</filename> as a repository,
480     because &SCons; will remove the current build directory
481     from its repository list for that invocation.)
482
483     </para>
484
485     <para>
486
487     Now, with the repository populated,
488     we only need to create the one local source file
489     we're interested in working with at the moment,
490     and use the <literal>-Y</literal> option to
491     tell &SCons; to fetch any other files it needs
492     from the repository:
493
494     </para>
495
496     <!--
497     <scons_output example="ex4">
498       <scons_output_command>cd $HOME/build</scons_output_command>
499       <scons_output_command>edit hello.c</scons_output_command>
500       <scons_output_command>scons -Q -Y __ROOT__/usr/repository1</scons_output_command>
501     </scons_output>
502     -->
503     <screen>
504       % <userinput>cd $HOME/build</userinput>
505       % <userinput>edit hello.c</userinput>
506       % <userinput>scons -Q -Y /usr/repository1</userinput>
507       cc -c -o hello.o hello.c
508       cc -o hello hello.o /usr/repository1/file1.o /usr/repository1/file2.o
509     </screen>
510
511     <para>
512
513     Notice that &SCons; realizes that it does not need to
514     rebuild local copies file1.o and file2.o files,
515     but instead uses the already-compiled files
516     from the repository.
517
518     </para>
519
520   </section>
521
522   <section>
523   <title>Guaranteeing local copies of files</title>
524
525     <para>
526
527     If the repository tree contains the complete results of a build,
528     and we try to build from the repository
529     without any files in our local tree,
530     something moderately surprising happens:
531
532     </para>
533
534     <screen>
535       % <userinput>mkdir $HOME/build2</userinput>
536       % <userinput>cd $HOME/build2</userinput>
537       % <userinput>scons -Q -Y /usr/all/repository hello</userinput>
538       scons: `hello' is up-to-date.
539     </screen>
540
541     <para>
542
543     Why does &SCons; say that the &hello; program
544     is up-to-date when there is no &hello; program
545     in the local build directory?
546     Because the repository (not the local directory)
547     contains the up-to-date &hello; program,
548     and &SCons; correctly determines that nothing
549     needs to be done to rebuild that
550     up-to-date copy of the file.
551
552     </para>
553
554     <para>
555
556     There are, however, many times when you want to ensure that a
557     local copy of a file always exists.
558     A packaging or testing script, for example,
559     may assume that certain generated files exist locally.
560     To tell &SCons; to make a copy of any up-to-date repository
561     file in the local build directory,
562     use the &Local; function:
563
564     </para>
565
566     <programlisting>
567        env = Environment()
568        hello = env.Program('hello.c')
569        Local(hello)
570     </programlisting>
571
572     <para>
573
574     If we then run the same command,
575     &SCons; will make a local copy of the program
576     from the repository copy,
577     and tell you that it is doing so:
578
579     </para>
580
581     <screen>
582       % <userinput>scons -Y /usr/all/repository hello</userinput>
583       Local copy of hello from /usr/all/repository/hello
584       scons: `hello' is up-to-date.
585     </screen>
586
587     <para>
588
589     (Notice that, because the act of making the local copy
590     is not considered a "build" of the &hello; file,
591     &SCons; still reports that it is up-to-date.)
592
593     </para>
594
595   </section>