Deprecate $WIN32 variables name in place of $WINDOWS* variables names, and eliminate...
[scons.git] / doc / user / builders-writing.sgml
1 <!--
2
3   __COPYRIGHT__
4
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:
12
13   The above copyright notice and this permission notice shall be included
14   in all copies or substantial portions of the Software.
15
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.
23
24 -->
25
26 <!--
27
28 =head2 Adding new methods
29
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:
35
36   # cons::InstallScript - Create a platform dependent version of a shell
37   # script by replacing string ``#!your-path-here'' with platform specific
38   # path $BIN_DIR.
39
40   sub cons::InstallScript {
41         my ($env, $dst, $src) = @_;
42         Command $env $dst, $src, qq(
43                 sed s+your-path-here+$BIN_DIR+ %< > %>
44                 chmod oug+x %>
45         );
46   }
47
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
51 following example:
52
53   InstallScript $env "$BIN/foo", "foo.tcl";
54
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
57 C<%BINDIR>.
58
59
60 =head2 Overriding methods
61
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
65 mechanisms.
66
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.
72
73   package cons::switch;
74   BEGIN {@ISA = 'cons'}
75
76   sub new {
77         shift;
78         bless new cons(@_);
79   }
80
81   sub Library {
82         my($env) = shift;
83         my($lib) = shift;
84         my(@objs) = Objects $env @_;
85         Command $env $lib, @objs, q(
86                 %LD -r %LDFLAGS %< -o %>
87         );
88   }
89
90 This functionality could be invoked as in the following example:
91
92   $env = new cons::switch(@overrides);
93   ...
94   Library $env 'lib.o', 'foo.c', 'bar.c';
95
96 -->
97
98   <para>
99
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.)
113
114   </para>
115
116   <section>
117   <title>Writing Builders That Execute External Commands</title>
118
119     <para>
120
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:
128
129     </para>
130
131     <programlisting>
132        bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
133     </programlisting>
134
135     <para>
136
137     All the above line does is create a free-standing
138     &Builder; object.
139     The next section will show us how to actually use it.
140
141     </para>
142
143   </section>
144
145   <section>
146   <title>Attaching a Builder to a &ConsEnv;</title>
147
148     <para>
149
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:
163
164     </para>
165
166     
167
168     <programlisting>
169        bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
170        env = Environment(BUILDERS = {'Foo' : bld})
171     </programlisting>
172
173     <para>
174
175     With the &Builder; so attached to our &consenv;
176     we can now actually call it like so:
177
178     </para>
179
180     <programlisting>
181        env.Foo('file.foo', 'file.input')
182     </programlisting>
183
184     <para>
185
186     Then when we run &SCons; it looks like:
187
188     </para>
189
190     <screen>
191       % <userinput>scons -Q</userinput>
192       foobuild &lt; file.input &gt; file.foo
193     </screen>
194
195     <para>
196
197     Note, however, that the default &cv-BUILDERS;
198     variable in a &consenv;
199     comes with a default set of &Builder; objects
200     already defined:
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
205     the environment:
206
207     </para>
208
209     <programlisting>
210        bld = Builder(action = 'foobuild &lt; $SOURCE &gt; $TARGET')
211        env = Environment(BUILDERS = {'Foo' : bld})
212        env.Foo('file.foo', 'file.input')
213        env.Program('hello.c')
214     </programlisting>
215
216     <screen>
217       % <userinput>scons -Q</userinput>
218       AttributeError: 'SConsEnvironment' object has no attribute 'Program':
219         File "SConstruct", line 4:
220           env.Program('hello.c')
221     </screen>
222
223     <para>
224
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:
229
230     </para>
231
232     
233
234     <programlisting>
235        env = Environment()
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')
240     </programlisting>
241
242     <para>
243
244     Or you can explicitly set the appropriately-named
245     key in the &cv-BUILDERS; dictionary:
246
247     </para>
248
249     <programlisting>
250        env = Environment()
251        bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
252        env['BUILDERS']['Foo'] = bld
253        env.Foo('file.foo', 'file.input')
254        env.Program('hello.c')
255     </programlisting>
256
257     <para>
258
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;:
263
264     </para>
265
266     <screen>
267       % <userinput>scons -Q</userinput>
268       foobuild &lt; file.input &gt; file.foo
269       cc -c -o hello.o hello.c
270       cc -o hello hello.o
271     </screen>
272
273   </section>
274
275   <section>
276   <title>Letting &SCons; Handle The File Suffixes</title>
277
278     <para>
279
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;:
292
293     </para>
294
295     
296
297     <programlisting>
298        bld = Builder(action = 'foobuild < $SOURCE > $TARGET',
299                      suffix = '.foo',
300                      src_suffix = '.input')
301        env = Environment(BUILDERS = {'Foo' : bld})
302        env.Foo('file1')
303        env.Foo('file2')
304     </programlisting>
305
306     <screen>
307       % <userinput>scons -Q</userinput>
308       foobuild &lt; file1.input &gt; file1.foo
309       foobuild &lt; file2.input &gt; file2.foo
310     </screen>
311
312     <para>
313
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.
317
318     </para>
319
320   </section>
321
322   <section>
323   <title>Builders That Execute Python Functions</title>
324
325     <para>
326
327     In &SCons;, you don't have to call an external command
328     to build a file.
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:
333
334     </para>
335
336     <programlisting>
337        def build_function(target, source, env):
338            # Code to build "target" from "source"
339            return None
340     </programlisting>
341
342     <para>
343
344     The arguments of a &buildfunc; are:
345
346     </para>
347
348     <variablelist>
349
350       <varlistentry>
351       <term>target</term>
352
353       <listitem>
354       <para>
355
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.
361
362       </para>
363       </listitem>
364       </varlistentry>
365
366       <varlistentry>
367       <term>source</term>
368
369       <listitem>
370       <para>
371
372       A list of Node objects representing
373       the sources to be
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.
377
378       </para>
379       </listitem>
380       </varlistentry>
381
382       <varlistentry>
383       <term>env</term>
384
385       <listitem>
386       <para>
387
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.
392
393       </para>
394       </listitem>
395       </varlistentry>
396
397     </variablelist>
398
399     <para>
400
401     The builder function must
402     return a <literal>0</literal> or <literal>None</literal> value
403     if the target(s) are built successfully.
404     The builder function
405     may raise an exception
406     or return any non-zero value
407     to indicate that the build is unsuccessful,
408
409     </para>
410
411     <para>
412
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,
418     as the &Builder;'s
419     <literal>action</literal>
420     argument:
421
422     </para>
423
424     <programlisting>
425        def build_function(target, source, env):
426            # Code to build "target" from "source"
427            return None
428        bld = Builder(action = build_function,
429                      suffix = '.foo',
430                      src_suffix = '.input')
431        env = Environment(BUILDERS = {'Foo' : bld})
432        env.Foo('file')
433     </programlisting>
434
435     <para>
436
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:
441
442     </para>
443
444     <screen>
445       % <userinput>scons -Q</userinput>
446       build_function(["file.foo"], ["file.input"])
447     </screen>
448
449   </section>
450
451   <section>
452   <title>Builders That Create Actions Using a &Generator;</title>
453
454     <para>
455
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:
462
463     </para>
464
465     <programlisting>
466        def generate_actions(source, target, env, for_signature):
467            return 'foobuild < %s > %s' % (target[0], source[0])
468     </programlisting>
469
470     <para>
471
472     The arguments of a &generator; are:
473
474     </para>
475
476     <variablelist>
477
478       <varlistentry>
479       <term>source</term>
480
481       <listitem>
482       <para>
483
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.
490
491       </para>
492       </listitem>
493
494       </varlistentry>
495
496       <varlistentry>
497       <term>target</term>
498
499       <listitem>
500       <para>
501
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.
508
509       </para>
510       </listitem>
511
512       </varlistentry>
513
514       <varlistentry>
515       <term>env</term>
516
517       <listitem>
518       <para>
519
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.
525
526       </para>
527       </listitem>
528
529       </varlistentry>
530
531       <varlistentry>
532       <term>for_signature</term>
533
534       <listitem>
535       <para>
536
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.
540
541       <!-- XXX NEED MORE HERE -->
542
543       </para>
544       </listitem>
545
546       </varlistentry>
547
548     </variablelist>
549
550     <para>
551
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).
555
556     </para>
557
558     <para>
559
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>.
564
565     </para>
566
567     
568
569     <programlisting>
570        def generate_actions(source, target, env, for_signature):
571            return 'foobuild < %s > %s' % (source[0], target[0])
572        bld = Builder(generator = generate_actions,
573                      suffix = '.foo',
574                      src_suffix = '.input')
575        env = Environment(BUILDERS = {'Foo' : bld})
576        env.Foo('file')
577     </programlisting>
578
579     <screen>
580       % <userinput>scons -Q</userinput>
581       foobuild &lt; file.input &gt; file.foo
582     </screen>
583
584     <para>
585
586     Note that it's illegal to specify both an
587     <literal>action</literal>
588     and a
589     <literal>generator</literal>
590     for a &Builder;.
591
592     </para>
593
594   </section>
595
596   <section>
597   <title>Builders That Modify the Target or Source Lists Using an &Emitter;</title>
598
599     <para>
600
601     &SCons; supports the ability for a Builder to modify the
602     lists of target(s) from the specified source(s).
603
604     </para>
605
606     
607
608     <programlisting>
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',
614                      suffix = '.foo',
615                      src_suffix = '.input',
616                      emitter = modify_targets)
617        env = Environment(BUILDERS = {'Foo' : bld})
618        env.Foo('file')
619     </programlisting>
620
621     <screen>
622       % <userinput>scons -Q</userinput>
623       foobuild file.foo new_target - file.input new_source
624     </screen>
625
626     <programlisting>
627        bld = Builder(action = 'XXX',
628                      suffix = '.foo',
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)
639        env1.Foo('file1')
640        env2.Foo('file2')
641     </programlisting>
642
643   </section>
644
645   <!--
646
647   <section>
648   <title>Builders That Use Other Builders</title>
649
650     <para>
651
652     XXX
653
654     </para>
655
656     <scons_example name="ex8">
657        <file name="SConstruct" printme="1">
658        env = Environment()
659        #env.SourceCode('.', env.BitKeeper('XXX'))
660        env.Program('hello.c')
661        </file>
662        <file name="hello.c">
663        hello.c
664        </file>
665     </scons_example>
666
667     <scons_output example="ex8">
668       <scons_output_command>scons -Q</scons_output_command>
669     </scons_output>
670
671   </section>
672
673   -->