[ci skip] update generated files
[scons.git] / doc / user / separate.xml
blob394bf6b4a0f399c10665ec3be2db43fa88526677
1 <?xml version='1.0'?>
3 <!--
4 SPDX-FileCopyrightText: Copyright The SCons Foundation (https://scons.org)
5 SPDX-License-Identifier: MIT
6 SPDX-FileType: DOCUMENTATION
8 This file is processed by the bin/SConsDoc.py module.
9 -->
11 <!DOCTYPE sconsdoc [
12     <!ENTITY % scons SYSTEM "../scons.mod">
13     %scons;
15     <!ENTITY % builders-mod SYSTEM "../generated/builders.mod">
16     %builders-mod;
17     <!ENTITY % functions-mod SYSTEM "../generated/functions.mod">
18     %functions-mod;
19     <!ENTITY % tools-mod SYSTEM "../generated/tools.mod">
20     %tools-mod;
21     <!ENTITY % variables-mod SYSTEM "../generated/variables.mod">
22     %variables-mod;
25 <chapter id="chap-separate"
26          xmlns="http://www.scons.org/dbxsd/v1.0"
27          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
28          xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
30 <title>Separating Source and Build Trees: Variant Directories</title>
32   <para>
34   It is often useful to keep built files completely
35   separate from the source files. Two main benefits are
36   the ability to have different configurations simultaneously
37   without build conflicts, and being version-control friendly.
39   </para>
41   <para>
43   Consider if you have a project to build an embedded
44   software system for a variety of different controller hardware.
45   The system is able to share a lot of code,
46   so it makes sense to use a common source tree,
47   but certain build options in the source code
48   and header files differ. For a regular in-place build,
49   the build outputs go in the same place as the source code.
50   If you build <emphasis>Controller A</emphasis> first,
51   followed by <emphasis>Controller B</emphasis>,
52   on the <emphasis>Controller B</emphasis> build everything that
53   uses different build options has to be rebuilt since those
54   objects will be different
55   (the build lines, including preprocessor defines, are part of
56   &SCons;'s out-of-date calculation for this reason).
57   If you go back and build for <emphasis>Controller A</emphasis> again,
58   things have to be rebuilt again for the same reason.
59   However, if you can separate the locations of the output files,
60   so each controller has its own location for build outputs,
61   this problem can be avoided.
63   </para>
65   <para>
67   Having a separated build tree also helps you keep your source tree clean -
68   there is less chance of accidentally checking in build products
69   to version control that were not intended to be checked in.
70   You can add a separated build directory to your
71   version control system's list of items not to track.
72   You can even remove the whole build tree with a single command without
73   risking removing any of the source code.
75   </para>
77   <para>
79   The key to making this separation work is the ability to
80   do out-of-tree builds: building under a separate root
81   than the sources being built.
82   You set up out-of-tree builds by establishing what &SCons;
83   calls a <firstterm>variant directory</firstterm>,
84   a place where you can build a single variant of your software
85   (of course you can define more than one of these if you need to).
86   Since &SCons; tracks targets by their path, it is able to distinguish
87   build products like <filename>build/A/network.obj</filename>
88   of the <emphasis>Controller A</emphasis> build
89   from <filename>build/B/network.obj</filename>
90   of the <emphasis>Controller B</emphasis> build,
91   thus avoiding conflicts.
93   </para>
95   <para>
97   &SCons; provides two ways to establish variant directories,
98   one through the &f-link-SConscript; function that we have already seen,
99   and the second through a more flexible &f-link-VariantDir; function.
101   </para>
103   <para>
105   The variant directory mechanism does support doing multiple builds
106   in one invocation of &SCons;, but the remainder of this chapter
107   will focus on setting up a single build. You can combine these
108   techniques with ones from the previous chapter and elsewhere
109   in this Guide to set up more complex scenarios.
111   </para>
113   <note> <para>
115   The &VariantDir; function used to be called &BuildDir;,
116   a name which was changed because it turned out to be confusing:
117   the &SCons; functionality
118   differs from a familiar model of a "build directory"
119   implemented by certain other build systems like GNU Autotools.
120   You might still find references to the old name on
121   the Internet in postings about &SCons;, but it no longer works.
123   </para> </note>
125   <section id="sect-variant-sconscript">
126   <title>Specifying a Variant Directory Tree as Part of an &SConscript; Call</title>
128     <para>
130     The most straightforward way to establish a variant directory tree
131     relies on the fact that the usual way to
132     set up a build hierarchy is to have an
133     &SConscript; file in the source directory.
134     If you pass a &variant_dir; argument to the
135     &f-link-SConscript; function call:
137     </para>
139     <scons_example name="separate_ex1">
140       <file name="SConstruct" printme="1">
141 SConscript('src/SConscript', variant_dir='build')
142       </file>
143       <file name="src/SConscript">
144 env = Environment()
145 env.Program('hello.c')
146       </file>
147       <file name="src/hello.c">
148 int main() { printf("Hello, world!\n"); }
149       </file>
150     </scons_example>
152     <para>
154     &SCons; will then build all of the files in
155     the &build; directory:
157     </para>
159     <scons_output example="separate_ex1" suffix="1">
160       <scons_output_command>ls src</scons_output_command>
161       <scons_output_command>scons -Q</scons_output_command>
162       <scons_output_command>ls src</scons_output_command>
163       <scons_output_command>ls build</scons_output_command>
164     </scons_output>
166     <para>
168     No files were built in &src;:
169     the object file
170     <filename>build/hello.o</filename>
171     and the executable file
172     <filename>build/hello</filename>
173     were built in the &build; directory, as expected.
174     But notice that even though our &hello_c; file actually
175     lives in the &src; directory, &SCons; has compiled a
176     <filename>build/hello.c</filename> file
177     to create the object file,
178     and that file is now seen in &build;.
180     </para>
182     <para>
184     You can ask &SCons; to show the dependency tree to illustrate
185     a bit more:
187     </para>
189     <scons_output example="separate_ex1" suffix="2">
190       <scons_output_command>scons -Q --tree=prune</scons_output_command>
191     </scons_output>
193     <para>
195     What's happened is that &SCons; has <emphasis>duplicated</emphasis>
196     the &hello_c; file from the &src; directory
197     to the &build; directory,
198     and built the program from there (it also duplicated &SConscript;).
199     The next section explains why &SCons; does this.
201     </para>
203     <para>
205     The nice thing about the &SConscript; approach is it is almost
206     invisible to you:
207     this build looks just like an ordinary in-place build
208     except for the extra &variant_dir; argument in the
209     &f-link-SConscript; call.
210     &SCons; handles all the path adjustments for the
211     out-of-tree &build; directory while it processes that SConscript file.
213     </para>
215   </section>
217   <section id="sect-variant-duplication">
218   <title>Why &SCons; Duplicates Source Files in a Variant Directory Tree</title>
220     <para>
222     When you set up a variant directory, &SCons; conceptually behaves as
223     if you requested a build in that directory.
224     As noted in the previous chapter,
225     all builds actually happen from the top level directory,
226     but as an aid to understanding how &SCons; operates, think
227     of it as <emphasis>build in place in the variant directory</emphasis>,
228     not <emphasis>build in source but send build artifacts
229     to the variant directory</emphasis>.
230     It turns out in place builds are easier to get right than out-of-tree
231     builds - so by default &SCons; simulates an in place build
232     by making the variant directory look just like the source directory.
233     The most straightforward way to do that is by making copies
234     of the files needed for the build.
236     </para>
238     <para>
240     The most direct reason to duplicate source files
241     in variant directories
242     is simply that some tools (mostly older versions)
243     are written to only build their output files
244     in the same directory as the source files - such tools often don't
245     have any option to specify the output file, and the tool just
246     uses a predefined output file name,
247     or uses a derived variant of the source file name,
248     dropping the result in the same directory.
249     In this case, the choices are either
250     to build the output file in the source directory
251     and move it to the variant directory,
252     or to duplicate the source files in the variant directory.
254     </para>
256     <para>
258     Additionally,
259     relative references between files
260     can cause problems which are resolved by
261     just duplicating the hierarchy of source files
262     into the variant directory.
263     You can see this at work in
264     use of the C preprocessor <literal>#include</literal>
265     mechanism with double quotes, not angle brackets:
267     </para>
269     <sconstruct>
270 #include "file.h"
271     </sconstruct>
273     <para>
275     The <emphasis>de facto</emphasis> standard behavior
276     for most C compilers in this case
277     is to first look in the same directory
278     as the source file that contains the <literal>#include</literal> line,
279     then to look in the directories in the preprocessor search path.
280     Add to this that the &SCons; implementation of
281     support for code repositories
282     (described below)
283     means not all of the files
284     will be found in the same directory hierarchy,
285     and the simplest way to make sure
286     that the right include file is found
287     is to duplicate the source files into the variant directory,
288     which provides a correct build
289     regardless of the original location(s) of the source files.
291     </para>
293     <para>
295     Although source-file duplication guarantees a correct build
296     even in these edge cases,
297     it can <emphasis>usually</emphasis> be safely disabled.
298     The next section describes
299     how you can disable the duplication of source files
300     in the variant directory.
302     </para>
304   </section>
306   <section id="sect-variant-no-duplication">
307   <title>Telling &SCons; to Not Duplicate Source Files in the Variant Directory Tree</title>
309     <para>
311     In most cases and with most tool sets,
312     &SCons; can use sources directly from the source directory
313     <emphasis>without</emphasis>
314     duplicating them into the variant directory before building,
315     and everything will work just fine.
316     You can disable the default &SCons; duplication behavior
317     by specifying <literal>duplicate=False</literal>
318     when you call the &f-link-SConscript; function:
320     </para>
322     <sconstruct>
323 SConscript('src/SConscript', variant_dir='build', duplicate=False)
324     </sconstruct>
326     <para>
328     When this flag is specified, the results of a build
329     look more like the mental model people may have from other
330     build systems - that is,
331     the output files end up in the variant directory
332     while the source files do not.
334     </para>
336     <screen>
337 % <userinput>ls src</userinput>
338 SConscript
339 hello.c
340 % <userinput>scons -Q</userinput>
341 cc -c src/hello.c -o build/hello.o
342 cc -o build/hello build/hello.o
343 % <userinput>ls build</userinput>
344 hello
345 hello.o
346     </screen>
348     <para>
350     If disabling duplication causes any problems,
351     just return to the more cautious approach by letting
352     &SCons; go back to duplicating files.
354     </para>
356   </section>
358   <section id="sect-variantdir-function">
359   <title>The &VariantDir; Function</title>
361     <para>
363     You can also use the &f-link-VariantDir; function to establish
364     that target files should be built in a separate directory tree
365     from the source files:
367     </para>
369     <scons_example name="separate_builddir">
370       <file name="SConstruct" printme="1">
371 VariantDir('build', 'src')
372 env = Environment()
373 env.Program('build/hello.c')
374       </file>
375       <file name="src/hello.c">
376 int main() { printf("Hello, world!\n"); }
377       </file>
378     </scons_example>
380     <para>
382     When using this form, you have to tell &SCons; that
383     sources and targets are in the variant directory,
384     and those references will trigger the remapping,
385     necessary file copying, etc. for an already established
386     variant directory.  Here is the same example in a more
387     spelled out form to show this more clearly:
389     <programlisting language="python">
390 VariantDir('build', 'src')
391 env = Environment()
392 env.Program(target='build/hello', source=['build/hello.c'])
393     </programlisting>
395     </para>
397     <para>
399     When using the &VariantDir; function directly,
400     &SCons; still duplicates the source files
401     in the variant directory by default:
403     </para>
405     <scons_output example="separate_builddir" suffix="1">
406       <scons_output_command>ls src</scons_output_command>
407       <scons_output_command>scons -Q</scons_output_command>
408       <scons_output_command>ls build</scons_output_command>
409     </scons_output>
411     <para>
413     You can specify the same <literal>duplicate=False</literal> argument
414     that you can specify for an &f-link-SConscript; call:
416     </para>
418     <scons_example name="separate_duplicate0">
419       <file name="SConstruct" printme="1">
420 VariantDir('build', 'src', duplicate=False)
421 env = Environment()
422 env.Program('build/hello.c')
423       </file>
424       <file name="src/hello.c">
425 int main() { printf("Hello, world!\n"); }
426       </file>
427     </scons_example>
429     <para>
431     In which case &SCons;
432     will disable duplication of the source files:
434     </para>
436     <scons_output example="separate_duplicate0" suffix="1">
437       <scons_output_command>ls src</scons_output_command>
438       <scons_output_command>scons -Q</scons_output_command>
439       <scons_output_command>ls build</scons_output_command>
440     </scons_output>
442   </section>
444   <section id="sect-variantdir-sconscript">
445   <title>Using &VariantDir; With an &SConscript; File</title>
447     <para>
449     Even when using the &f-link-VariantDir; function,
450     it is more natural to use it with
451     a subsidiary &SConscript; file,
452     because then you don't have to adjust your individual
453     build instructions to use the variant directory path.
454     For example, if the
455     <filename>src/SConscript</filename>
456     looks like this:
458     </para>
460     <scons_example name="separate_builddir_sconscript">
461       <file name="SConstruct">
462 VariantDir('build', 'src')
463 SConscript('build/SConscript')
464       </file>
465       <file name="src/SConscript" printme="1">
466 env = Environment()
467 env.Program('hello.c')
468       </file>
469       <file name="src/hello.c">
470 int main() { printf("Hello, world!\n"); }
471       </file>
472     </scons_example>
474     <para>
476     Then our &SConstruct; file could look like:
478     </para>
480     <scons_example_file example="separate_builddir_sconscript" name="SConstruct">
481     </scons_example_file>
483     <para>
485     Yielding the following output:
487     </para>
489     <scons_output example="separate_builddir_sconscript" suffix="1">
490       <scons_output_command>ls src</scons_output_command>
491       <scons_output_command>scons -Q</scons_output_command>
492       <scons_output_command>ls build</scons_output_command>
493     </scons_output>
495     <para>
497     This is completely equivalent
498     to the use of &f-link-SConscript; with the
499     <parameter>variant_dir</parameter> argument
500     from earlier in this chapter,
501     but did require calling the SConscript using the already established
502     variant directory path to trigger that behavior.
503     If you call <userinput>SConscript('src/SConscript')</userinput>
504     you would get a normal in-place build in &src;.
506     </para>
508   </section>
510   <section id="sect-variantdir-glob">
511   <title>Using &Glob; with &VariantDir;</title>
513     <para>
515     The &f-link-Glob; file name pattern matching function
516     works just as usual when using &f-link-VariantDir;.
517     For example, if the
518     <filename>src/SConscript</filename>
519     looks like this:
521     </para>
523     <scons_example name="separate_glob_builddir_sconscript">
524       <file name="SConstruct">
525 VariantDir('build', 'src')
526 SConscript('build/SConscript')
527       </file>
528       <file name="src/SConscript" printme="1">
529 env = Environment()
530 env.Program('hello', Glob('*.c'))
531       </file>
532       <file name="src/f1.c">
533 #include "f2.h"
534 int main() { printf(f2()); }
535       </file>
536       <file name="src/f2.c">
537 const char * f2() { return("Hello, world!\n"); }
538       </file>
539       <file name="src/f2.h">
540 const char * f2();
541       </file>
542     </scons_example>
544     <para>
546     Then with the same &SConstruct; file as in the previous section,
547     and source files <filename>f1.c</filename>
548     and <filename>f2.c</filename> in src,
549     we would see the following output:
551     </para>
553     <scons_output example="separate_glob_builddir_sconscript" suffix="1">
554       <scons_output_command>ls src</scons_output_command>
555       <scons_output_command>scons -Q</scons_output_command>
556       <scons_output_command>ls build</scons_output_command>
557     </scons_output>
559     <para>
561     The &Glob; function returns Nodes in the
562     <filename>build/</filename> tree, as you'd expect.
564     </para>
566   </section>
568   <!--
570   <section id="sect-variantdir-over-sconscript">
571   <title>Why You'd Want to Call &VariantDir; Instead of &SConscript;</title>
573     <para>
575     XXX why call VariantDir() instead of SConscript(variant_dir=)
577     </para>
579   </section>
581   -->
583   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="variants.xml"/>
585 </chapter>