3 Copyright (c) 2001, 2002, 2003 Steven Knight
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:
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
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.
28 Here's the famous "Hello, World!" program in C:
36 printf("Hello, world!\n");
42 And here's how to build it using &SCons;.
43 Enter the following into a file named &SConstruct;:
47 <scons_example name="ex1">
48 <file name="SConstruct" printme="1">
50 env.Program('hello.c')
53 int main() { printf("Hello, world!\n"); }
59 That's it. Now run the &scons; command to build the program.
60 On a POSIX-compliant system like Linux or UNIX,
61 you'll see something like:
65 <scons_output example="ex1" os="posix">
66 <command>scons</command>
71 On a Windows system with the Microsoft Visual C++ compiler,
72 you'll see something like:
76 <scons_output example="ex1" os="win32">
77 <command>scons</command>
82 First, notice that you only need
83 to specify the name of the source file,
84 and that &SCons; deduces the names of
85 the object and executable files
86 correctly from the base of the source file name.
92 Second, notice that the same input &SConstruct; file,
94 generates the correct output file names on both systems:
95 <filename>hello.o</filename> and <filename>hello</filename>
97 <filename>hello.obj</filename> and <filename>hello.exe</filename>
99 This is a simple example of how &SCons;
100 makes it extremely easy to
101 write portable software builds.
107 (Note that we won't provide duplicate side-by-side
108 POSIX and Windows output for all of the examples in this guide;
109 just keep in mind that, unless otherwise specified,
110 any of the examples should work equally well on both types of systems.)
115 <title>The &SConstruct; File</title>
119 If you're used to build systems like &Make;
120 you've already figured out that the &SConstruct; file
121 is the &SCons; equivalent of a &Makefile;.
122 That is, the &SConstruct; file is the input file
123 that &SCons; reads to control the build.
129 There is, however, an important difference between
130 an &SConstruct; file and a &Makefile;:
131 the &SConstruct; file is actually a Python script.
132 If you're not already familiar with Python, don't worry.
133 This User's Guide will introduce you step-by-step
134 to the relatively small amount of Python you'll
135 need to know to be able to use &SCons; effectively.
136 And Python is very easy to learn.
142 One aspect of using Python as the
143 scripting language is that you can put comments
144 in your &SConstruct; file using Python's commenting convention;
145 that is, everything between a '#' and the end of the line
151 env = Environment() # Create an environment.
152 # Arrange to build the "hello" program.
153 env.Program('hello.c')
158 You'll see throughout the remainder of this Guide
159 that being able to use the power of a
160 real scripting language
161 can greatly simplify the solutions
162 to complex requirements of real-world builds.
169 <title>Compiling Multiple Source Files</title>
173 You've just seen how to configure &SCons;
174 to compile a program from a single source file.
175 It's more common, of course,
176 that you'll need to build a program from
177 many input source files, not just one.
178 To do this, you need to put the
179 source files in a Python list
180 (enclosed in square brackets),
185 <scons_example name="ex2">
186 <file name="SConstruct" printme="1">
188 env.Program(['prog.c', 'file1.c', 'file2.c'])
191 int main() { printf("prog.c\n"); }
193 <file name="file1.c">
194 void file1() { printf("file1.c\n"); }
196 <file name="file2.c">
197 void file2() { printf("file2.c\n"); }
203 A build of the above example would look like:
207 <scons_output example="ex2">
208 <command>scons</command>
214 deduces the output program name
215 from the first source file specified
216 in the list--that is,
217 because the first source file was &prog_c;,
218 &SCons; will name the resulting program &prog;
219 (or &prog_exe; on a Windows system).
220 If you want to specify a different program name,
221 then you slide the list of source files
223 to make room for the output program file name.
224 (&SCons; puts the output file name to the left
225 of the source file names
226 so that the order mimics that of an
227 assignment statement: "program = source files".)
228 This makes our example:
232 <scons_example name="ex3">
233 <file name="SConstruct" printme="1">
235 env.Program('program', ['main.c', 'file1.c', 'file2.c'])
238 int main() { printf("prog.c\n"); }
240 <file name="file1.c">
241 void file1() { printf("file1.c\n"); }
243 <file name="file2.c">
244 void file2() { printf("file2.c\n"); }
250 On Linux, a build of this example would look like:
254 <scons_output example="ex3" os="posix">
255 <command>scons</command>
264 <scons_output example="ex3" os="win32">
265 <command>scons</command>
271 <title>Keeping &SConstruct; Files Easy to Read</title>
275 One drawback to the use of a Python list
276 for source files is that
277 each file name must be enclosed in quotes
278 (either single quotes or double quotes).
279 This can get cumbersome and difficult to read
280 when the list of file names is long.
281 Fortunately, &SCons; and Python provide a number of ways
283 the &SConstruct; file stays easy to read.
289 To make long lists of file names
290 easier to deal with, &SCons; provides a
292 that takes a quoted list of file names,
293 with the names separated by spaces or other white-space characters,
294 and turns it into a list of separate file names.
295 Using the &Split; function turns the
296 previous example into:
302 env.Program('program', Split('main.c file1.c file2.'))
307 Putting the call to the &Split; function
308 inside the <function>env.Program</function> call
309 can also be a little unwieldy.
310 A more readable alternative is to
311 assign the output from the &Split; call
313 and then use the variable when calling the
314 <function>env.Program</function> function:
320 list = Split('main.c file1.c file2.')
321 env.Program('program', list)
326 Lastly, the &Split; function
327 doesn't care how much white space separates
328 the file names in the quoted string.
329 This allows you to create lists of file
330 names that span multiple lines,
331 which often makes for easier editing:
340 env.Program('program', list)
346 <title>Keyword Arguments</title>
350 &SCons; also allows you to identify
351 the output file and input source files
352 using Python keyword arguments.
353 The output file is known as the
354 <emphasis>target</emphasis>,
355 and the source file(s) are known (logically enough) as the
356 <emphasis>source</emphasis>.
357 The Python syntax for this is:
363 list = Split('main.c file1.c file2.')
364 env.Program(target = 'program', source = list)
369 Whether or not you choose to use keyword arguments
370 to identify the target and source files
371 is purely a personal choice;
372 &SCons; functions the same either way.
379 <title>Compiling Multiple Programs</title>
383 In order to compile multiple programs
384 within the same &SConstruct; file,
385 simply call the <function>env.Program</function> method
387 once for each program you need to build:
391 <scons_example name="ex4">
392 <file name="SConstruct" printme="1">
395 env.Program('bar', ['bar1.c', 'bar2.c'])
398 int main() { printf("foo.c\n"); }
401 int main() { printf("bar1.c\n"); }
404 void bar2() { printf("bar2.c\n"); }
410 &SCons; would then build the programs as follows:
414 <scons_output example="ex4">
415 <command>scons</command>
420 Notice that &SCons; does not necessarily build the
421 programs in the same order in which you specify
422 them in the &SConstruct; file.
423 &SCons; does, however, recognize that
424 the individual object files must be built
425 before the resulting program can be built.
426 We'll discuss this in greater detail in
427 the "Dependencies" section, below.
434 <title>Sharing Source Files Between Multiple Programs</title>
438 It's common to re-use code by sharing source files
439 between multiple programs.
440 One way to do this is to create a library
441 from the common source files,
442 which can then be linked into resulting programs.
443 (Creating libraries is discussed in
450 A more straightforward, but perhaps less convenient,
451 way to share source files between multiple programs
452 is simply to include the common files
453 in the lists of source files for each program:
457 <scons_example name="ex5">
458 <file name="SConstruct" printme="1">
460 env.Program(Split('foo.c common1.c common2.c'))
461 env.Program('bar', Split('bar1.c bar2.c common1.c common2.c'))
464 int main() { printf("foo.c\n"); }
467 int main() { printf("bar1.c\n"); }
470 int bar2() { printf("bar2.c\n"); }
472 <file name="common1.c">
473 void common1() { printf("common1.c\n"); }
475 <file name="common2.c">
476 void common22() { printf("common2.c\n"); }
482 &SCons; recognizes that the object files for
483 the &common1_c; and &common2_c; source files
484 each only need to be built once,
485 even though the files are listed multiple times:
489 <scons_output example="ex5">
490 <command>scons</command>
495 If two or more programs
496 share a lot of common source files,
497 repeating the common files in the list for each program
498 can be a maintenance problem when you need to change the
499 list of common files.
500 You can simplify this by creating a separate Python list
501 to hold the common file names,
502 and concatenating it with other lists
503 using the Python + operator:
508 common = ['common1.c', 'common2.c']
509 foo_files = ['foo.c'] + common
510 bar_files = ['bar1.c', 'bar2.c'] + common
512 env.Program('foo', foo_files)
513 env.Program('bar', bar_files)
518 This is functionally equivalent to the previous example.