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 =head2 Adding new methods
30 For slightly more demanding changes, you may wish to add new methods to the
31 C<cons> package. Here's an example of a very simple extension,
32 C<InstallScript>, which installs a tcl script in a requested location, but
33 edits the script first to reflect a platform-dependent path that needs to be
34 installed in the script:
36 # cons::InstallScript - Create a platform dependent version of a shell
37 # script by replacing string ``#!your-path-here'' with platform specific
40 sub cons::InstallScript {
41 my ($env, $dst, $src) = @_;
42 Command $env $dst, $src, qq(
43 sed s+your-path-here+$BIN_DIR+ %< > %>
48 Notice that this method is defined directly in the C<cons> package (by
49 prefixing the name with C<cons::>). A change made in this manner will be
50 globally visible to all environments, and could be called as in the
53 InstallScript $env "$BIN/foo", "foo.tcl";
55 For a small improvement in generality, the C<BINDIR> variable could be
56 passed in as an argument or taken from the construction environment-,-as
60 =head2 Overriding methods
62 Instead of adding the method to the C<cons> name space, you could define a
63 new package which inherits existing methods from the C<cons> package and
64 overrides or adds others. This can be done using Perl's inheritance
67 The following example defines a new package C<cons::switch> which
68 overrides the standard C<Library> method. The overridden method builds
69 linked library modules, rather than library archives. A new
70 constructor is provided. Environments created with this constructor
71 will have the new library method; others won't.
84 my(@objs) = Objects $env @_;
85 Command $env $lib, @objs, q(
86 %LD -r %LDFLAGS %< -o %>
90 This functionality could be invoked as in the following example:
92 $env = new cons::switch(@overrides);
94 Library $env 'lib.o', 'foo.c', 'bar.c';
100 Although &SCons; provides many useful methods
101 for building common software products:
102 programs, libraries, documents.
103 you frequently want to be
104 able to build some other type of file
105 not supported directly by &SCons;
106 Fortunately, &SCons; makes it very easy
107 to define your own &Builder; objects
108 for any custom file types you want to build.
109 (In fact, the &SCons; interfaces for creating
110 &Builder; objects are flexible enough and easy enough to use
111 that all of the the &SCons; built-in &Builder; objects
112 are created the mechanisms described in this section.)
117 <title>Writing Builders That Execute External Commands</title>
121 The simplest &Builder; to create is
122 one that executes an external command.
123 For example, if we want to build
124 an output file by running the contents
125 of the input file through a command named
126 <literal>foobuild</literal>,
127 creating that &Builder; might look like:
132 bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
137 All the above line does is create a free-standing
139 The next section will show us how to actually use it.
146 <title>Attaching a Builder to a &ConsEnv;</title>
150 A &Builder; object isn't useful
151 until it's attached to a &consenv;
152 so that we can call it to arrange
153 for files to be built.
154 This is done through the &cv-link-BUILDERS;
155 &consvar; in an environment.
156 The &cv-BUILDERS; variable is a Python dictionary
157 that maps the names by which you want to call
158 various &Builder; objects to the objects themselves.
159 For example, if we want to call the
160 &Builder; we just defined by the name
161 <function>Foo</function>,
162 our &SConstruct; file might look like:
169 bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
170 env = Environment(BUILDERS = {'Foo' : bld})
175 With the &Builder; so attached to our &consenv;
176 we can now actually call it like so:
181 env.Foo('file.foo', 'file.input')
186 Then when we run &SCons; it looks like:
191 % <userinput>scons -Q</userinput>
192 foobuild < file.input > file.foo
197 Note, however, that the default &cv-BUILDERS;
198 variable in a &consenv;
199 comes with a default set of &Builder; objects
201 &b-link-Program;, &b-link-Library;, etc.
202 And when we explicitly set the &cv-BUILDERS; variable
203 when we create the &consenv;,
204 the default &Builder;s are no longer part of
210 bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
211 env = Environment(BUILDERS = {'Foo' : bld})
212 env.Foo('file.foo', 'file.input')
213 env.Program('hello.c')
217 % <userinput>scons -Q</userinput>
218 AttributeError: 'SConsEnvironment' object has no attribute 'Program':
219 File "SConstruct", line 4:
220 env.Program('hello.c')
225 To be able use both our own defined &Builder; objects
226 and the default &Builder; objects in the same &consenv;,
227 you can either add to the &cv-BUILDERS; variable
228 using the &Append; function:
236 bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
237 env.Append(BUILDERS = {'Foo' : bld})
238 env.Foo('file.foo', 'file.input')
239 env.Program('hello.c')
244 Or you can explicitly set the appropriately-named
245 key in the &cv-BUILDERS; dictionary:
251 bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
252 env['BUILDERS']['Foo'] = bld
253 env.Foo('file.foo', 'file.input')
254 env.Program('hello.c')
259 Either way, the same &consenv;
260 can then use both the newly-defined
261 <function>Foo</function> &Builder;
262 and the default &b-link-Program; &Builder;:
267 % <userinput>scons -Q</userinput>
268 foobuild < file.input > file.foo
269 cc -c -o hello.o hello.c
276 <title>Letting &SCons; Handle The File Suffixes</title>
280 By supplying additional information
281 when you create a &Builder;,
282 you can let &SCons; add appropriate file
283 suffixes to the target and/or the source file.
284 For example, rather than having to specify
285 explicitly that you want the <literal>Foo</literal>
286 &Builder; to build the <literal>file.foo</literal>
287 target file from the <literal>file.input</literal> source file,
288 you can give the <literal>.foo</literal>
289 and <literal>.input</literal> suffixes to the &Builder;,
290 making for more compact and readable calls to
291 the <literal>Foo</literal> &Builder;:
298 bld = Builder(action = 'foobuild < $SOURCE > $TARGET',
300 src_suffix = '.input')
301 env = Environment(BUILDERS = {'Foo' : bld})
307 % <userinput>scons -Q</userinput>
308 foobuild < file1.input > file1.foo
309 foobuild < file2.input > file2.foo
314 You can also supply a <literal>prefix</literal> keyword argument
315 if it's appropriate to have &SCons; append a prefix
316 to the beginning of target file names.
323 <title>Builders That Execute Python Functions</title>
327 In &SCons;, you don't have to call an external command
329 You can, instead, define a Python function
330 that a &Builder; object can invoke
331 to build your target file (or files).
332 Such a &buildfunc; definition looks like:
337 def build_function(target, source, env):
338 # Code to build "target" from "source"
344 The arguments of a &buildfunc; are:
356 A list of Node objects representing
357 the target or targets to be
358 built by this builder function.
359 The file names of these target(s)
360 may be extracted using the Python &str; function.
372 A list of Node objects representing
374 used by this builder function to build the targets.
375 The file names of these source(s)
376 may be extracted using the Python &str; function.
388 The &consenv; used for building the target(s).
389 The builder function may use any of the
390 environment's construction variables
391 in any way to affect how it builds the targets.
401 The builder function must
402 return a <literal>0</literal> or <literal>None</literal> value
403 if the target(s) are built successfully.
405 may raise an exception
406 or return any non-zero value
407 to indicate that the build is unsuccessful,
413 Once you've defined the Python function
414 that will build your target file,
415 defining a &Builder; object for it is as
416 simple as specifying the name of the function,
417 instead of an external command,
419 <literal>action</literal>
425 def build_function(target, source, env):
426 # Code to build "target" from "source"
428 bld = Builder(action = build_function,
430 src_suffix = '.input')
431 env = Environment(BUILDERS = {'Foo' : bld})
437 And notice that the output changes slightly,
438 reflecting the fact that a Python function,
439 not an external command,
440 is now called to build the target file:
445 % <userinput>scons -Q</userinput>
446 build_function(["file.foo"], ["file.input"])
452 <title>Builders That Create Actions Using a &Generator;</title>
456 &SCons; Builder objects can create an action "on the fly"
457 by using a function called a &generator;.
458 This provides a great deal of flexibility to
459 construct just the right list of commands
460 to build your target.
461 A &generator; looks like:
466 def generate_actions(source, target, env, for_signature):
467 return 'foobuild < %s > %s' % (target[0], source[0])
472 The arguments of a &generator; are:
484 A list of Node objects representing
485 the sources to be built
486 by the command or other action
487 generated by this function.
488 The file names of these source(s)
489 may be extracted using the Python &str; function.
502 A list of Node objects representing
503 the target or targets to be built
504 by the command or other action
505 generated by this function.
506 The file names of these target(s)
507 may be extracted using the Python &str; function.
520 The &consenv; used for building the target(s).
521 The generator may use any of the
522 environment's construction variables
523 in any way to determine what command
524 or other action to return.
532 <term>for_signature</term>
537 A flag that specifies whether the
538 generator is being called to contribute to a build signature,
539 as opposed to actually executing the command.
541 <!-- XXX NEED MORE HERE -->
552 The &generator; must return a
553 command string or other action that will be used to
554 build the specified target(s) from the specified source(s).
560 Once you've defined a &generator;,
561 you create a &Builder; to use it
562 by specifying the generator keyword argument
563 instead of <literal>action</literal>.
570 def generate_actions(source, target, env, for_signature):
571 return 'foobuild < %s > %s' % (source[0], target[0])
572 bld = Builder(generator = generate_actions,
574 src_suffix = '.input')
575 env = Environment(BUILDERS = {'Foo' : bld})
580 % <userinput>scons -Q</userinput>
581 foobuild < file.input > file.foo
586 Note that it's illegal to specify both an
587 <literal>action</literal>
589 <literal>generator</literal>
597 <title>Builders That Modify the Target or Source Lists Using an &Emitter;</title>
601 &SCons; supports the ability for a Builder to modify the
602 lists of target(s) from the specified source(s).
609 def modify_targets(target, source, env):
610 target.append('new_target')
611 source.append('new_source')
612 return target, source
613 bld = Builder(action = 'foobuild $TARGETS - $SOURCES',
615 src_suffix = '.input',
616 emitter = modify_targets)
617 env = Environment(BUILDERS = {'Foo' : bld})
622 % <userinput>scons -Q</userinput>
623 foobuild file.foo new_target - file.input new_source
627 bld = Builder(action = 'XXX',
629 src_suffix = '.input',
630 emitter = 'MY_EMITTER')
631 def modify1(target, source, env):
632 return target, source
633 def modify2(target, source, env):
634 return target, source
635 env1 = Environment(BUILDERS = {'Foo' : bld},
636 MY_EMITTER = modify1)
637 env2 = Environment(BUILDERS = {'Foo' : bld},
638 MY_EMITTER = modify2)
648 <title>Builders That Use Other Builders</title>
656 <scons_example name="ex8">
657 <file name="SConstruct" printme="1">
659 #env.SourceCode('.', env.BitKeeper('XXX'))
660 env.Program('hello.c')
662 <file name="hello.c">
667 <scons_output example="ex8">
668 <scons_output_command>scons -Q</scons_output_command>