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.
12 <!ENTITY % scons SYSTEM "../scons.mod">
15 <!ENTITY % builders-mod SYSTEM "../generated/builders.mod">
17 <!ENTITY % functions-mod SYSTEM "../generated/functions.mod">
19 <!ENTITY % tools-mod SYSTEM "../generated/tools.mod">
21 <!ENTITY % variables-mod SYSTEM "../generated/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>
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.
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.
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.
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.
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.
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.
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.
125 <section id="sect-variant-sconscript">
126 <title>Specifying a Variant Directory Tree as Part of an &SConscript; Call</title>
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:
139 <scons_example name="separate_ex1">
140 <file name="SConstruct" printme="1">
141 SConscript('src/SConscript', variant_dir='build')
143 <file name="src/SConscript">
145 env.Program('hello.c')
147 <file name="src/hello.c">
148 int main() { printf("Hello, world!\n"); }
154 &SCons; will then build all of the files in
155 the &build; directory:
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>
168 No files were built in &src;:
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;.
184 You can ask &SCons; to show the dependency tree to illustrate
189 <scons_output example="separate_ex1" suffix="2">
190 <scons_output_command>scons -Q --tree=prune</scons_output_command>
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.
205 The nice thing about the &SConscript; approach is it is almost
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.
217 <section id="sect-variant-duplication">
218 <title>Why &SCons; Duplicates Source Files in a Variant Directory Tree</title>
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.
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.
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:
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
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.
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.
306 <section id="sect-variant-no-duplication">
307 <title>Telling &SCons; to Not Duplicate Source Files in the Variant Directory Tree</title>
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:
323 SConscript('src/SConscript', variant_dir='build', duplicate=False)
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.
337 % <userinput>ls src</userinput>
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>
350 If disabling duplication causes any problems,
351 just return to the more cautious approach by letting
352 &SCons; go back to duplicating files.
358 <section id="sect-variantdir-function">
359 <title>The &VariantDir; Function</title>
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:
369 <scons_example name="separate_builddir">
370 <file name="SConstruct" printme="1">
371 VariantDir('build', 'src')
373 env.Program('build/hello.c')
375 <file name="src/hello.c">
376 int main() { printf("Hello, world!\n"); }
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')
392 env.Program(target='build/hello', source=['build/hello.c'])
399 When using the &VariantDir; function directly,
400 &SCons; still duplicates the source files
401 in the variant directory by default:
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>
413 You can specify the same <literal>duplicate=False</literal> argument
414 that you can specify for an &f-link-SConscript; call:
418 <scons_example name="separate_duplicate0">
419 <file name="SConstruct" printme="1">
420 VariantDir('build', 'src', duplicate=False)
422 env.Program('build/hello.c')
424 <file name="src/hello.c">
425 int main() { printf("Hello, world!\n"); }
431 In which case &SCons;
432 will disable duplication of the source files:
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>
444 <section id="sect-variantdir-sconscript">
445 <title>Using &VariantDir; With an &SConscript; File</title>
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.
455 <filename>src/SConscript</filename>
460 <scons_example name="separate_builddir_sconscript">
461 <file name="SConstruct">
462 VariantDir('build', 'src')
463 SConscript('build/SConscript')
465 <file name="src/SConscript" printme="1">
467 env.Program('hello.c')
469 <file name="src/hello.c">
470 int main() { printf("Hello, world!\n"); }
476 Then our &SConstruct; file could look like:
480 <scons_example_file example="separate_builddir_sconscript" name="SConstruct">
481 </scons_example_file>
485 Yielding the following output:
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>
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;.
510 <section id="sect-variantdir-glob">
511 <title>Using &Glob; with &VariantDir;</title>
515 The &f-link-Glob; file name pattern matching function
516 works just as usual when using &f-link-VariantDir;.
518 <filename>src/SConscript</filename>
523 <scons_example name="separate_glob_builddir_sconscript">
524 <file name="SConstruct">
525 VariantDir('build', 'src')
526 SConscript('build/SConscript')
528 <file name="src/SConscript" printme="1">
530 env.Program('hello', Glob('*.c'))
532 <file name="src/f1.c">
534 int main() { printf(f2()); }
536 <file name="src/f2.c">
537 const char * f2() { return("Hello, world!\n"); }
539 <file name="src/f2.h">
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:
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>
561 The &Glob; function returns Nodes in the
562 <filename>build/</filename> tree, as you'd expect.
570 <section id="sect-variantdir-over-sconscript">
571 <title>Why You'd Want to Call &VariantDir; Instead of &SConscript;</title>
575 XXX why call VariantDir() instead of SConscript(variant_dir=)
583 <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="variants.xml"/>