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-less-simple"
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>Less Simple Things to Do With Builds</title>
34 Of course, most builds are more complicated than in the previous chapter.
36 you will learn about builds that incorporate multiple source files,
37 and then about building multiple targets that share some source files.
41 <section id="sect-target-name">
42 <title>Specifying the Name of the Target (Output) File</title>
46 You've seen that when you call the &b-link-Program; builder method,
47 it builds the resulting program with the same
48 base name as the source file.
49 That is, the following call to build an
50 executable program from the &hello_c; source file
51 will build an executable program named &hello; on POSIX systems,
52 and an executable program named &hello_exe; on Windows systems:
62 If you want to build a program with
63 a different base name than the base of the source file name
64 (or even the same name),
65 you simply put the target file name
66 to the left of the source file name:
70 <scons_example name="lesssimple_target">
71 <file name="SConstruct" printme="1">
72 Program('new_hello', 'hello.c')
75 int main() { printf("Hello, world!\n"); }
81 &SCons; requires the target file name first,
82 followed by the source file name,
83 so that the order mimics that of an
84 assignment statement in most programming languages,
86 <literal>"target = source files"</literal>. For an
87 alternative way to supply this information, see
88 <xref linkend="sect-keyword-args"></xref>.
94 Now &SCons; will build an executable program
95 named &new_hello; when run on a POSIX system:
99 <scons_output example="lesssimple_target" os="posix" suffix="1">
100 <scons_output_command>scons -Q</scons_output_command>
105 And &SCons; will build an executable program
106 named &new_hello_exe; when run on a Windows system:
110 <scons_output example="lesssimple_target" os="win32" suffix="2">
111 <scons_output_command>scons -Q</scons_output_command>
116 <section id="sect-multi-source">
117 <title>Compiling Multiple Source Files</title>
121 You've just seen how to configure &SCons;
122 to compile a program from a single source file.
123 It's more common, of course,
124 that you'll need to build a program from
125 many input source files, not just one.
126 To do this, you need to put the
127 source files in a &Python; list
128 (enclosed in square brackets),
133 <scons_example name="lesssimple_ex2">
134 <file name="SConstruct" printme="1">
135 Program(['prog.c', 'file1.c', 'file2.c'])
138 int main() { printf("prog.c\n"); }
140 <file name="file1.c">
141 void file1() { printf("file1.c\n"); }
143 <file name="file2.c">
144 void file2() { printf("file2.c\n"); }
150 A build of the above example would look like:
154 <scons_output example="lesssimple_ex2" suffix="1">
155 <scons_output_command>scons -Q</scons_output_command>
161 deduces the output program name
162 from the first source file specified
163 in the list--that is,
164 because the first source file was &prog_c;,
165 &SCons; will name the resulting program &prog;
166 (or &prog_exe; on a Windows system).
167 If you want to specify a different program name,
168 then (as described in the previous section)
169 you slide the list of source files
171 to make room for the output program file name.
172 Here is the updated example:
176 <scons_example name="lesssimple_ex3">
177 <file name="SConstruct" printme="1">
178 Program('program', ['prog.c', 'file1.c', 'file2.c'])
181 int main() { printf("prog.c\n"); }
183 <file name="file1.c">
184 void file1() { printf("file1.c\n"); }
186 <file name="file2.c">
187 void file2() { printf("file2.c\n"); }
193 On Linux, a build of this example would look like:
197 <scons_output example="lesssimple_ex3" os="posix" suffix="1">
198 <scons_output_command>scons -Q</scons_output_command>
207 <scons_output example="lesssimple_ex3" os="win32" suffix="2">
208 <scons_output_command>scons -Q</scons_output_command>
213 <section id="sect-glob-source">
214 <title>Making a list of files with &Glob;</title>
218 You can also use the &f-link-Glob; function to find all files matching a
219 certain template, using the standard shell pattern matching
220 characters <literal>*</literal> (to match everything),
221 <literal>?</literal> (to match a single character)
222 and <literal>[abc]</literal> to match any of
223 <literal>a</literal>, <literal>b</literal> or <literal>c</literal>.
224 <literal>[!abc]</literal> is also supported,
225 to match any character <emphasis>except</emphasis>
226 <literal>a</literal>, <literal>b</literal> or <literal>c</literal>.
227 This makes many multi-source-file builds quite easy:
232 Program('program', Glob('*.c'))
237 &f-Glob; has powerful capabilities - it matches even if the
238 file does not currently exist,
239 but &SCons; can determine that it would
241 You will meet it again reading about
243 (see <xref linkend="chap-separate"/>)
245 (see <xref linkend="chap-repositories"/>).
251 <section id="sect-single-list">
252 <title>Specifying Single Files Vs. Lists of Files</title>
256 You've now seen two ways to specify
257 the source for a program,
258 one with a list of files:
263 Program('hello', ['file1.c', 'file2.c'])
268 And one with a single file:
273 Program('hello', 'hello.c')
278 You can actually put a single file name in a list, too,
279 which you might prefer just for the sake of consistency:
284 Program('hello', ['hello.c'])
289 &SCons; functions will accept a single file name in either form.
290 In fact, internally, &SCons; treats all input as lists of files,
291 but allows you to omit the square brackets
292 to cut down a little on the typing
293 when there's only a single file name.
301 Although &SCons; functions
302 are forgiving about whether or not you
303 use a string vs. a list for a single file name,
304 &Python; itself is stricter about
305 treating lists and strings differently.
306 So where &SCons; allows either
312 # The following two calls both work correctly:
313 Program('program1', 'program1.c')
314 Program('program2', ['program2.c'])
319 Trying to do "&Python; things" that mix strings and
320 lists will cause errors or lead to incorrect results:
325 common_sources = ['file1.c', 'file2.c']
327 # THE FOLLOWING IS INCORRECT AND GENERATES A PYTHON ERROR
328 # BECAUSE IT TRIES TO ADD A STRING TO A LIST:
329 Program('program1', common_sources + 'program1.c')
331 # The following works correctly, because it's adding two
332 # lists together to make another list.
333 Program('program2', common_sources + ['program2.c'])
340 <section id="sect-source-split">
341 <title>Making Lists of Files Easier to Read</title>
345 One drawback to the use of a &Python; list
346 for source files is that
347 each file name must be enclosed in quotes
348 (either single quotes or double quotes).
349 This can get cumbersome and difficult to read
350 when the list of file names is long.
351 Fortunately, &SCons; and &Python; provide a number of ways
353 the &SConstruct; file stays easy to read.
359 To make long lists of file names
360 easier to deal with, &SCons; provides a
361 &f-link-Split; function
362 that takes a quoted list of file names,
363 with the names separated by spaces or other white-space characters,
364 and turns it into a list of separate file names.
365 Using the &Split; function turns the
366 previous example into:
371 Program('program', Split('main.c file1.c file2.c'))
376 (If you're already familiar with &Python;,
377 you'll have realized that this is similar to the
378 <function>split()</function> method
379 of &Python; string objects.
380 Unlike the <function>split()</function> method,
381 however, the &Split; function
382 does not require a string as input
383 and will wrap up a single non-string object in a list,
384 or return its argument untouched if it's already a list.
385 This comes in handy as a way to make sure
386 arbitrary values can be passed to &SCons; functions
387 without having to check the type of the variable by hand.)
393 Putting the call to the &Split; function
394 inside the &b-Program; call
395 can also be a little unwieldy.
396 A more readable alternative is to
397 assign the output from the &Split; call
399 and then use the variable when calling the
400 &b-Program; function:
405 src_files = Split('main.c file1.c file2.c')
406 Program('program', src_files)
411 Lastly, the &Split; function
412 doesn't care how much white space separates
413 the file names in the quoted string.
414 This allows you to create lists of file
415 names that span multiple lines,
416 which often makes for easier editing:
421 src_files = Split("""
426 Program('program', src_files)
431 (Note this example uses
432 the &Python; "triple-quote" syntax,
433 which allows a string to span multiple lines.
434 The three quotes can be either
435 single or double quotes as long as they match.)
441 <section id="sect-keyword-args">
442 <title>Keyword Arguments</title>
446 &SCons; also allows you to identify
447 the output file and input source files
448 using &Python; <firstterm>keyword arguments</firstterm>
449 <parameter>target</parameter> and
450 <parameter>source</parameter>.
451 A keyword argument is an argument preceded by an identifier,
452 of the form <literal>name=value</literal>, in a function call.
453 The usage looks like this example:
458 src_files = Split('main.c file1.c file2.c')
459 Program(target='program', source=src_files)
464 Because the keywords explicitly identify
465 what each argument is, the order does
466 not matter and you can reverse it if you prefer:
471 src_files = Split('main.c file1.c file2.c')
472 Program(source=src_files, target='program')
477 Whether or not you choose to use keyword arguments
478 to identify the target and source files,
479 and the order in which you specify them
481 are purely personal choices;
482 &SCons; functions the same regardless.
488 <section id="sect-multi-targets">
489 <title>Compiling Multiple Programs</title>
493 In order to compile multiple programs
494 within the same &SConstruct; file,
495 simply call the &Program; method
497 once for each program you need to build:
501 <scons_example name="lesssimple_ex4">
502 <file name="SConstruct" printme="1">
504 Program('bar', ['bar1.c', 'bar2.c'])
507 int main() { printf("foo.c\n"); }
510 int main() { printf("bar1.c\n"); }
513 void bar2() { printf("bar2.c\n"); }
519 &SCons; would then build the programs as follows:
523 <scons_output example="lesssimple_ex4" suffix="1">
524 <scons_output_command>scons -Q</scons_output_command>
529 Notice that &SCons; does not necessarily build the
530 programs in the same order in which you specify
531 them in the &SConstruct; file.
532 &SCons; does, however, recognize that
533 the individual object files must be built
534 before the resulting program can be built.
535 (This will be covered in greater detail in
536 <xref linkend="chap-depends"/>, below.)
542 <section id="sect-sharing-sources">
543 <title>Sharing Source Files Between Multiple Programs</title>
547 It's common to re-use code by sharing source files
548 between multiple programs.
549 One way to do this is to create a library
550 from the common source files,
551 which can then be linked into resulting programs.
552 (Creating libraries is discussed in
553 <xref linkend="chap-libraries"></xref>, below.)
559 A more straightforward, but perhaps less convenient,
560 way to share source files between multiple programs
561 is simply to include the common files
562 in the lists of source files for each program:
566 <scons_example name="lesssimple_ex5">
567 <file name="SConstruct" printme="1">
568 Program(Split('foo.c common1.c common2.c'))
569 Program('bar', Split('bar1.c bar2.c common1.c common2.c'))
572 int main() { printf("foo.c\n"); }
575 int main() { printf("bar1.c\n"); }
578 int bar2() { printf("bar2.c\n"); }
580 <file name="common1.c">
581 void common1() { printf("common1.c\n"); }
583 <file name="common2.c">
584 void common22() { printf("common2.c\n"); }
590 &SCons; recognizes that the object files for
591 the &common1_c; and &common2_c; source files
592 each need to be built only once,
593 even though the resulting object files are
594 each linked in to both of the resulting executable programs:
598 <scons_output example="lesssimple_ex5" suffix="1">
599 <scons_output_command>scons -Q</scons_output_command>
604 If two or more programs
605 share a lot of common source files,
606 repeating the common files in the list for each program
607 can be a maintenance problem when you need to change the
608 list of common files.
609 You can simplify this by creating a separate &Python; list
610 to hold the common file names,
611 and concatenating it with other lists
612 using the &Python; + operator:
617 common = ['common1.c', 'common2.c']
618 foo_files = ['foo.c'] + common
619 bar_files = ['bar1.c', 'bar2.c'] + common
620 Program('foo', foo_files)
621 Program('bar', bar_files)
626 This is functionally equivalent to the previous example.