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 The ToolSurrogate stuff that's used to capture output initializes
211 SCons.Defaults.ConstructionEnvironment with its own list of TOOLS.
212 In this next example, we want to show the user that when they
213 set the BUILDERS explicitly, the call to env.Program() generates
214 an AttributeError. This won't happen with all of the default
215 ToolSurrogates in the default construction environment. To make the
216 AttributeError show up, we have to overwite the default construction
217 environment's TOOLS variable so Program() builder doesn't show up.
219 We do this by executing a slightly different SConstruct file than the
220 one we print in the guide, with two extra statements at the front
221 that overwrite the TOOLS variable as described. Note that we have
222 to jam those statements on to the first line to keep the line number
223 in the generated error consistent with what the user will see in the
227 bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
228 env = Environment(BUILDERS = {'Foo' : bld})
229 env.Foo('file.foo', 'file.input')
230 env.Program('hello.c')
234 % <userinput>scons -Q</userinput>
235 AttributeError: SConsEnvironment instance has no attribute 'Program':
236 File "/home/my/project/SConstruct", line 4:
237 env.Program('hello.c')
242 To be able use both our own defined &Builder; objects
243 and the default &Builder; objects in the same &consenv;,
244 you can either add to the &cv-BUILDERS; variable
245 using the &Append; function:
253 bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
254 env.Append(BUILDERS = {'Foo' : bld})
255 env.Foo('file.foo', 'file.input')
256 env.Program('hello.c')
261 Or you can explicitly set the appropriately-named
262 key in the &cv-BUILDERS; dictionary:
268 bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
269 env['BUILDERS']['Foo'] = bld
270 env.Foo('file.foo', 'file.input')
271 env.Program('hello.c')
276 Either way, the same &consenv;
277 can then use both the newly-defined
278 <function>Foo</function> &Builder;
279 and the default &b-link-Program; &Builder;:
284 % <userinput>scons -Q</userinput>
285 foobuild < file.input > file.foo
286 cc -o hello.o -c hello.c
293 <title>Letting &SCons; Handle The File Suffixes</title>
297 By supplying additional information
298 when you create a &Builder;,
299 you can let &SCons; add appropriate file
300 suffixes to the target and/or the source file.
301 For example, rather than having to specify
302 explicitly that you want the <literal>Foo</literal>
303 &Builder; to build the <literal>file.foo</literal>
304 target file from the <literal>file.input</literal> source file,
305 you can give the <literal>.foo</literal>
306 and <literal>.input</literal> suffixes to the &Builder;,
307 making for more compact and readable calls to
308 the <literal>Foo</literal> &Builder;:
315 bld = Builder(action = 'foobuild < $SOURCE > $TARGET',
317 src_suffix = '.input')
318 env = Environment(BUILDERS = {'Foo' : bld})
324 % <userinput>scons -Q</userinput>
325 foobuild < file1.input > file1.foo
326 foobuild < file2.input > file2.foo
331 You can also supply a <literal>prefix</literal> keyword argument
332 if it's appropriate to have &SCons; append a prefix
333 to the beginning of target file names.
340 <title>Builders That Execute Python Functions</title>
344 In &SCons;, you don't have to call an external command
346 You can, instead, define a Python function
347 that a &Builder; object can invoke
348 to build your target file (or files).
349 Such a &buildfunc; definition looks like:
354 def build_function(target, source, env):
355 # Code to build "target" from "source"
361 The arguments of a &buildfunc; are:
373 A list of Node objects representing
374 the target or targets to be
375 built by this builder function.
376 The file names of these target(s)
377 may be extracted using the Python &str; function.
389 A list of Node objects representing
391 used by this builder function to build the targets.
392 The file names of these source(s)
393 may be extracted using the Python &str; function.
405 The &consenv; used for building the target(s).
406 The builder function may use any of the
407 environment's construction variables
408 in any way to affect how it builds the targets.
418 The builder function must
419 return a <literal>0</literal> or <literal>None</literal> value
420 if the target(s) are built successfully.
422 may raise an exception
423 or return any non-zero value
424 to indicate that the build is unsuccessful,
430 Once you've defined the Python function
431 that will build your target file,
432 defining a &Builder; object for it is as
433 simple as specifying the name of the function,
434 instead of an external command,
436 <literal>action</literal>
442 def build_function(target, source, env):
443 # Code to build "target" from "source"
445 bld = Builder(action = build_function,
447 src_suffix = '.input')
448 env = Environment(BUILDERS = {'Foo' : bld})
454 And notice that the output changes slightly,
455 reflecting the fact that a Python function,
456 not an external command,
457 is now called to build the target file:
462 % <userinput>scons -Q</userinput>
463 build_function(["file.foo"], ["file.input"])
469 <title>Builders That Create Actions Using a &Generator;</title>
473 &SCons; Builder objects can create an action "on the fly"
474 by using a function called a &generator;.
475 This provides a great deal of flexibility to
476 construct just the right list of commands
477 to build your target.
478 A &generator; looks like:
483 def generate_actions(source, target, env, for_signature):
484 return 'foobuild < %s > %s' % (target[0], source[0])
489 The arguments of a &generator; are:
501 A list of Node objects representing
502 the sources to be built
503 by the command or other action
504 generated by this function.
505 The file names of these source(s)
506 may be extracted using the Python &str; function.
519 A list of Node objects representing
520 the target or targets to be built
521 by the command or other action
522 generated by this function.
523 The file names of these target(s)
524 may be extracted using the Python &str; function.
537 The &consenv; used for building the target(s).
538 The generator may use any of the
539 environment's construction variables
540 in any way to determine what command
541 or other action to return.
549 <term>for_signature</term>
554 A flag that specifies whether the
555 generator is being called to contribute to a build signature,
556 as opposed to actually executing the command.
558 <!-- XXX NEED MORE HERE, describe generators use in signatures -->
569 The &generator; must return a
570 command string or other action that will be used to
571 build the specified target(s) from the specified source(s).
577 Once you've defined a &generator;,
578 you create a &Builder; to use it
579 by specifying the generator keyword argument
580 instead of <literal>action</literal>.
587 def generate_actions(source, target, env, for_signature):
588 return 'foobuild < %s > %s' % (source[0], target[0])
589 bld = Builder(generator = generate_actions,
591 src_suffix = '.input')
592 env = Environment(BUILDERS = {'Foo' : bld})
597 % <userinput>scons -Q</userinput>
598 foobuild < file.input > file.foo
603 Note that it's illegal to specify both an
604 <literal>action</literal>
606 <literal>generator</literal>
614 <title>Builders That Modify the Target or Source Lists Using an &Emitter;</title>
618 &SCons; supports the ability for a Builder to modify the
619 lists of target(s) from the specified source(s).
626 def modify_targets(target, source, env):
627 target.append('new_target')
628 source.append('new_source')
629 return target, source
630 bld = Builder(action = 'foobuild $TARGETS - $SOURCES',
632 src_suffix = '.input',
633 emitter = modify_targets)
634 env = Environment(BUILDERS = {'Foo' : bld})
639 % <userinput>scons -Q</userinput>
640 foobuild file.foo new_target - file.input new_source
644 bld = Builder(action = 'my_command',
646 src_suffix = '.input',
647 emitter = 'MY_EMITTER')
648 def modify1(target, source, env):
649 return target, source
650 def modify2(target, source, env):
651 return target, source
652 env1 = Environment(BUILDERS = {'Foo' : bld},
653 MY_EMITTER = modify1)
654 env2 = Environment(BUILDERS = {'Foo' : bld},
655 MY_EMITTER = modify2)
665 <title>Builders That Use Other Builders</title>
673 <scons_example name="ex8">
674 <file name="SConstruct" printme="1">
676 #env.SourceCode('.', env.BitKeeper('my_command'))
677 env.Program('hello.c')
679 <file name="hello.c">
684 <scons_output example="ex8">
685 <scons_output_command>scons -Q</scons_output_command>