2c5cce2409099e7c3b82a62419ead6a5368d7384
[scons.git] / doc / user / builders-writing.in
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     <scons_example name="ex1">
167        <file name="SConstruct">
168        bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
169        env = Environment(BUILDERS = {'Foo' : bld})
170        import os
171        env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd()
172        env.Foo('file.foo', 'file.input')
173        </file>
174        <file name="file.input">
175        file.input
176        </file>
177        <file name="foobuild" chmod="0755">
178        cat
179        </file>
180     </scons_example>
181
182     <sconstruct>
183        bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
184        env = Environment(BUILDERS = {'Foo' : bld})
185     </sconstruct>
186
187     <para>
188
189     With the &Builder; attached to our &consenv;
190     with the name <function>Foo</function>,
191     we can now actually call it like so:
192
193     </para>
194
195     <programlisting>
196        env.Foo('file.foo', 'file.input')
197     </programlisting>
198
199     <para>
200
201     Then when we run &SCons; it looks like:
202
203     </para>
204
205     <scons_output example="ex1">
206       <scons_output_command>scons -Q</scons_output_command>
207     </scons_output>
208
209     <para>
210
211     Note, however, that the default &cv-BUILDERS;
212     variable in a &consenv;
213     comes with a default set of &Builder; objects
214     already defined:
215     &b-link-Program;, &b-link-Library;, etc.
216     And when we explicitly set the &cv-BUILDERS; variable
217     when we create the &consenv;,
218     the default &Builder;s are no longer part of
219     the environment:
220
221     </para>
222
223    <!--
224    The ToolSurrogate stuff that's used to capture output initializes
225    SCons.Defaults.ConstructionEnvironment with its own list of TOOLS.
226    In this next example, we want to show the user that when they
227    set the BUILDERS explicitly, the call to env.Program() generates
228    an AttributeError.  This won't happen with all of the default
229    ToolSurrogates in the default construction environment.  To make the
230    AttributeError show up, we have to overwite the default construction
231    environment's TOOLS variable so Program() builder doesn't show up.
232
233    We do this by executing a slightly different SConstruct file than the
234    one we print in the guide, with two extra statements at the front
235    that overwrite the TOOLS variable as described.  Note that we have
236    to jam those statements on to the first line to keep the line number
237    in the generated error consistent with what the user will see in the
238    User's Guide.
239    -->
240     <scons_example name="ex2">
241        <file name="SConstruct">
242        import SCons.Defaults; SCons.Defaults.ConstructionEnvironment['TOOLS'] = {}; bld = Builder(action = 'foobuild &lt; $SOURCE &gt; $TARGET')
243        env = Environment(BUILDERS = {'Foo' : bld})
244        env.Foo('file.foo', 'file.input')
245        env.Program('hello.c')
246        </file>
247        <file name="SConstruct.printme" printme="1">
248        bld = Builder(action = 'foobuild &lt; $SOURCE &gt; $TARGET')
249        env = Environment(BUILDERS = {'Foo' : bld})
250        env.Foo('file.foo', 'file.input')
251        env.Program('hello.c')
252        </file>
253        <file name="file.input">
254        file.input
255        </file>
256        <file name="hello.c">
257        hello.c
258        </file>
259     </scons_example>
260
261     <scons_output example="ex2">
262       <scons_output_command>scons -Q</scons_output_command>
263     </scons_output>
264
265     <para>
266
267     To be able to use both our own defined &Builder; objects
268     and the default &Builder; objects in the same &consenv;,
269     you can either add to the &cv-BUILDERS; variable
270     using the &Append; function:
271
272     </para>
273
274     <scons_example name="ex3">
275        <file name="SConstruct">
276        env = Environment()
277        import os
278        env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd()
279        bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
280        env.Append(BUILDERS = {'Foo' : bld})
281        env.Foo('file.foo', 'file.input')
282        env.Program('hello.c')
283        </file>
284        <file name="file.input">
285        file.input
286        </file>
287        <file name="hello.c">
288        hello.c
289        </file>
290        <file name="foobuild" chmod="0755">
291        cat
292        </file>
293     </scons_example>
294
295     <sconstruct>
296        env = Environment()
297        bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
298        env.Append(BUILDERS = {'Foo' : bld})
299        env.Foo('file.foo', 'file.input')
300        env.Program('hello.c')
301     </sconstruct>
302
303     <para>
304
305     Or you can explicitly set the appropriately-named
306     key in the &cv-BUILDERS; dictionary:
307
308     </para>
309
310     <sconstruct>
311        env = Environment()
312        bld = Builder(action = 'foobuild < $SOURCE > $TARGET')
313        env['BUILDERS']['Foo'] = bld
314        env.Foo('file.foo', 'file.input')
315        env.Program('hello.c')
316     </sconstruct>
317
318     <para>
319
320     Either way, the same &consenv;
321     can then use both the newly-defined
322     <function>Foo</function> &Builder;
323     and the default &b-link-Program; &Builder;:
324
325     </para>
326
327     <scons_output example="ex3">
328       <scons_output_command>scons -Q</scons_output_command>
329     </scons_output>
330
331   </section>
332
333   <section>
334   <title>Letting &SCons; Handle The File Suffixes</title>
335
336     <para>
337
338     By supplying additional information
339     when you create a &Builder;,
340     you can let &SCons; add appropriate file
341     suffixes to the target and/or the source file.
342     For example, rather than having to specify
343     explicitly that you want the <literal>Foo</literal>
344     &Builder; to build the <literal>file.foo</literal>
345     target file from the <literal>file.input</literal> source file,
346     you can give the <literal>.foo</literal>
347     and <literal>.input</literal> suffixes to the &Builder;,
348     making for more compact and readable calls to
349     the <literal>Foo</literal> &Builder;:
350
351     </para>
352
353     <scons_example name="ex4">
354        <file name="SConstruct">
355        bld = Builder(action = 'foobuild < $SOURCE > $TARGET',
356                      suffix = '.foo',
357                      src_suffix = '.input')
358        env = Environment(BUILDERS = {'Foo' : bld})
359        import os
360        env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd()
361        env.Foo('file1')
362        env.Foo('file2')
363        </file>
364        <file name="file1.input">
365        file1.input
366        </file>
367        <file name="file2.input">
368        file2.input
369        </file>
370        <file name="foobuild" chmod="0755">
371        cat
372        </file>
373     </scons_example>
374
375     <sconstruct>
376        bld = Builder(action = 'foobuild < $SOURCE > $TARGET',
377                      suffix = '.foo',
378                      src_suffix = '.input')
379        env = Environment(BUILDERS = {'Foo' : bld})
380        env.Foo('file1')
381        env.Foo('file2')
382     </sconstruct>
383
384     <scons_output example="ex4">
385       <scons_output_command>scons -Q</scons_output_command>
386     </scons_output>
387
388     <para>
389
390     You can also supply a <literal>prefix</literal> keyword argument
391     if it's appropriate to have &SCons; append a prefix
392     to the beginning of target file names.
393
394     </para>
395
396   </section>
397
398   <section>
399   <title>Builders That Execute Python Functions</title>
400
401     <para>
402
403     In &SCons;, you don't have to call an external command
404     to build a file.
405     You can, instead, define a Python function
406     that a &Builder; object can invoke
407     to build your target file (or files).
408     Such a &buildfunc; definition looks like:
409
410     </para>
411
412     <programlisting>
413        def build_function(target, source, env):
414            # Code to build "target" from "source"
415            return None
416     </programlisting>
417
418     <para>
419
420     The arguments of a &buildfunc; are:
421
422     </para>
423
424     <variablelist>
425
426       <varlistentry>
427       <term>target</term>
428
429       <listitem>
430       <para>
431
432       A list of Node objects representing
433       the target or targets to be
434       built by this builder function.
435       The file names of these target(s)
436       may be extracted using the Python &str; function.
437
438       </para>
439       </listitem>
440       </varlistentry>
441
442       <varlistentry>
443       <term>source</term>
444
445       <listitem>
446       <para>
447
448       A list of Node objects representing
449       the sources to be
450       used by this builder function to build the targets.
451       The file names of these source(s)
452       may be extracted using the Python &str; function.
453
454       </para>
455       </listitem>
456       </varlistentry>
457
458       <varlistentry>
459       <term>env</term>
460
461       <listitem>
462       <para>
463
464       The &consenv; used for building the target(s).
465       The builder function may use any of the
466       environment's construction variables
467       in any way to affect how it builds the targets.
468
469       </para>
470       </listitem>
471       </varlistentry>
472
473     </variablelist>
474
475     <para>
476
477     The builder function must
478     return a <literal>0</literal> or <literal>None</literal> value
479     if the target(s) are built successfully.
480     The builder function
481     may raise an exception
482     or return any non-zero value
483     to indicate that the build is unsuccessful,
484
485     </para>
486
487     <para>
488
489     Once you've defined the Python function
490     that will build your target file,
491     defining a &Builder; object for it is as
492     simple as specifying the name of the function,
493     instead of an external command,
494     as the &Builder;'s
495     <literal>action</literal>
496     argument:
497
498     </para>
499
500     <scons_example name="ex5">
501        <file name="SConstruct" printme="1">
502        def build_function(target, source, env):
503            # Code to build "target" from "source"
504            return None
505        bld = Builder(action = build_function,
506                      suffix = '.foo',
507                      src_suffix = '.input')
508        env = Environment(BUILDERS = {'Foo' : bld})
509        env.Foo('file')
510        </file>
511        <file name="file.input">
512        file.input
513        </file>
514     </scons_example>
515
516     <para>
517
518     And notice that the output changes slightly,
519     reflecting the fact that a Python function,
520     not an external command,
521     is now called to build the target file:
522
523     </para>
524
525     <scons_output example="ex5">
526       <scons_output_command>scons -Q</scons_output_command>
527     </scons_output>
528
529   </section>
530
531   <section>
532   <title>Builders That Create Actions Using a &Generator;</title>
533
534     <para>
535
536     &SCons; Builder objects can create an action "on the fly"
537     by using a function called a &generator;.
538     This provides a great deal of flexibility to
539     construct just the right list of commands
540     to build your target.
541     A &generator; looks like:
542
543     </para>
544
545     <programlisting>
546        def generate_actions(source, target, env, for_signature):
547            return 'foobuild < %s > %s' % (target[0], source[0])
548     </programlisting>
549
550     <para>
551
552     The arguments of a &generator; are:
553
554     </para>
555
556     <variablelist>
557
558       <varlistentry>
559       <term>source</term>
560
561       <listitem>
562       <para>
563
564       A list of Node objects representing
565       the sources to be built
566       by the command or other action
567       generated by this function.
568       The file names of these source(s)
569       may be extracted using the Python &str; function.
570
571       </para>
572       </listitem>
573
574       </varlistentry>
575
576       <varlistentry>
577       <term>target</term>
578
579       <listitem>
580       <para>
581
582       A list of Node objects representing
583       the target or targets to be built
584       by the command or other action
585       generated by this function.
586       The file names of these target(s)
587       may be extracted using the Python &str; function.
588
589       </para>
590       </listitem>
591
592       </varlistentry>
593
594       <varlistentry>
595       <term>env</term>
596
597       <listitem>
598       <para>
599
600       The &consenv; used for building the target(s).
601       The generator may use any of the
602       environment's construction variables
603       in any way to determine what command
604       or other action to return.
605
606       </para>
607       </listitem>
608
609       </varlistentry>
610
611       <varlistentry>
612       <term>for_signature</term>
613
614       <listitem>
615       <para>
616
617       A flag that specifies whether the
618       generator is being called to contribute to a build signature,
619       as opposed to actually executing the command.
620
621       <!-- XXX NEED MORE HERE, describe generators use in signatures -->
622
623       </para>
624       </listitem>
625
626       </varlistentry>
627
628     </variablelist>
629
630     <para>
631
632     The &generator; must return a
633     command string or other action that will be used to
634     build the specified target(s) from the specified source(s).
635
636     </para>
637
638     <para>
639
640     Once you've defined a &generator;,
641     you create a &Builder; to use it
642     by specifying the generator keyword argument
643     instead of <literal>action</literal>.
644
645     </para>
646
647     <scons_example name="ex6">
648        <file name="SConstruct">
649        def generate_actions(source, target, env, for_signature):
650            return 'foobuild < %s > %s' % (source[0], target[0])
651        bld = Builder(generator = generate_actions,
652                      suffix = '.foo',
653                      src_suffix = '.input')
654        env = Environment(BUILDERS = {'Foo' : bld})
655        import os
656        env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd()
657        env.Foo('file')
658        </file>
659        <file name="file.input">
660        file.input
661        </file>
662        <file name="foobuild" chmod="0755">
663        cat
664        </file>
665     </scons_example>
666
667     <sconstruct>
668        def generate_actions(source, target, env, for_signature):
669            return 'foobuild < %s > %s' % (source[0], target[0])
670        bld = Builder(generator = generate_actions,
671                      suffix = '.foo',
672                      src_suffix = '.input')
673        env = Environment(BUILDERS = {'Foo' : bld})
674        env.Foo('file')
675     </sconstruct>
676
677     <scons_output example="ex6">
678       <scons_output_command>scons -Q</scons_output_command>
679     </scons_output>
680
681     <para>
682
683     Note that it's illegal to specify both an
684     <literal>action</literal>
685     and a
686     <literal>generator</literal>
687     for a &Builder;.
688
689     </para>
690
691   </section>
692
693   <section>
694   <title>Builders That Modify the Target or Source Lists Using an &Emitter;</title>
695
696     <para>
697
698     &SCons; supports the ability for a Builder to modify the
699     lists of target(s) from the specified source(s).
700     You do this by defining an &emitter; function
701     that takes as its arguments
702     the list of the targets passed to the builder,
703     the list of the sources passed to the builder,
704     and the construction environment.
705     The emitter function should return the modified
706     lists of targets that should be built
707     and sources from which the targets will be built.
708
709     </para>
710
711     <para>
712
713     For example, suppose you want to define a Builder
714     that always calls a <filename>foobuild</filename> program,
715     and you want to automatically add
716     a new target file named
717     <filename>new_target</filename>
718     and a new source file named
719     <filename>new_source</filename>
720     whenever it's called.
721     The &SConstruct; file might look like this:
722
723     </para>
724
725     <scons_example name="ex7">
726        <file name="SConstruct">
727        def modify_targets(target, source, env):
728            target.append('new_target')
729            source.append('new_source')
730            return target, source
731        bld = Builder(action = 'foobuild $TARGETS - $SOURCES',
732                      suffix = '.foo',
733                      src_suffix = '.input',
734                      emitter = modify_targets)
735        env = Environment(BUILDERS = {'Foo' : bld})
736        import os
737        env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd()
738        env.Foo('file')
739        </file>
740        <file name="file.input">
741        file.input
742        </file>
743        <file name="new_source">
744        new_source
745        </file>
746        <file name="foobuild" chmod="0755">
747        cat
748        </file>
749     </scons_example>
750
751     <sconstruct>
752        def modify_targets(target, source, env):
753            target.append('new_target')
754            source.append('new_source')
755            return target, source
756        bld = Builder(action = 'foobuild $TARGETS - $SOURCES',
757                      suffix = '.foo',
758                      src_suffix = '.input',
759                      emitter = modify_targets)
760        env = Environment(BUILDERS = {'Foo' : bld})
761        env.Foo('file')
762     </sconstruct>
763
764     <para>
765     
766     And would yield the following output:
767
768     </para>
769
770     <scons_output example="ex7">
771       <scons_output_command>scons -Q</scons_output_command>
772     </scons_output>
773
774     <para>
775
776     One very flexible thing that you can do is
777     use a construction variable to specify
778     different emitter functions for different
779     construction variable.
780     To do this, specify a string
781     containing a construction variable
782     expansion as the emitter when you call
783     the &Builder; function,
784     and set that construction variable to
785     the desired emitter function
786     in different construction environments:
787
788     </para>
789
790     <scons_example name="MY_EMITTER">
791
792       <file name="SConstruct" printme="1">
793         bld = Builder(action = 'my_command $SOURCES > $TARGET',
794                       suffix = '.foo',
795                       src_suffix = '.input',
796                       emitter = '$MY_EMITTER')
797         def modify1(target, source, env):
798             return target, source + ['modify1.in']
799         def modify2(target, source, env):
800             return target, source + ['modify2.in']
801         env1 = Environment(BUILDERS = {'Foo' : bld},
802                            MY_EMITTER = modify1)
803         env2 = Environment(BUILDERS = {'Foo' : bld},
804                            MY_EMITTER = modify2)
805         env1.Foo('file1')
806         env2.Foo('file2')
807         import os
808         env1['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd()
809         env2['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd()
810         </file>
811         <file name="file1.input">
812         file1.input
813         </file>
814         <file name="file2.input">
815         file2.input
816         </file>
817         <file name="modify1.in">
818         modify1.input
819         </file>
820         <file name="modify2.in">
821         modify2.input
822         </file>
823         <file name="my_command" chmod="0755">
824         cat
825         </file>
826       </file>
827
828     </scons_example>
829
830     <sconstruct>
831       bld = Builder(action = 'my_command $SOURCES > $TARGET',
832                     suffix = '.foo',
833                     src_suffix = '.input',
834                     emitter = '$MY_EMITTER')
835       def modify1(target, source, env):
836           return target, source + ['modify1.in']
837       def modify2(target, source, env):
838           return target, source + ['modify2.in']
839       env1 = Environment(BUILDERS = {'Foo' : bld},
840                          MY_EMITTER = modify1)
841       env2 = Environment(BUILDERS = {'Foo' : bld},
842                          MY_EMITTER = modify2)
843       env1.Foo('file1')
844       env2.Foo('file2')
845       </file>
846     </sconstruct>
847
848     <para>
849
850     In this example, the <filename>modify1.in</filename>
851     and <filename>modify2.in</filename> files
852     get added to the source lists
853     of the different commands:
854
855     </para>
856
857     <scons_output example="MY_EMITTER">
858       <scons_output_command>scons -Q</scons_output_command>
859     </scons_output>
860
861   </section>
862
863   <!--
864
865   <section>
866   <title>target_factor=, source_factory=</title>
867
868   </section>
869
870   <section>
871   <title>target_scanner=, source_scanner=</title>
872
873   </section>
874
875   <section>
876   <title>multi=</title>
877
878   </section>
879
880   <section>
881   <title>single_source=</title>
882
883   </section>
884
885   <section>
886   <title>src_builder=</title>
887
888   </section>
889
890   <section>
891   <title>ensure_suffix=</title>
892
893   </section>
894
895   -->
896
897   <section>
898   <title>Where To Put Your Custom Builders and Tools</title>
899
900     <para>
901
902     The <filename>site_scons</filename> directory gives you a place to
903     put Python modules you can import into your &SConscript; files
904     (<filename>site_scons</filename>),
905     add-on tools that can integrate into &SCons;
906     (<filename>site_scons/site_tools</filename>),
907     and a <filename>site_scons/site_init.py</filename> file that
908     gets read before any &SConstruct; or &SConscript; file,
909     allowing you to change &SCons;'s default behavior.
910
911     </para>
912
913     <para>
914
915     If you get a tool from somewhere (the &SCons; wiki or a third party,
916     for instance) and you'd like to use it in your project, the
917     <filename>site_scons</filename> dir is the simplest place to put it.
918     Tools come in two flavors; either a Python function that operates on
919     an &Environment; or a Python file containing two functions,
920     <function>exists()</function> and <function>generate()</function>.
921
922     </para>
923
924     <para>
925
926     A single-function Tool can just be included in your
927     <filename>site_scons/site_init.py</filename> file where it will be
928     parsed and made available for use.  For instance, you could have a
929     <filename>site_scons/site_init.py</filename> file like this:
930
931     </para>
932
933     <scons_example name="site1">
934       <file name="site_scons/site_init.py" printme=1>
935         def TOOL_ADD_HEADER(env):
936            """A Tool to add a header from $HEADER to the source file"""
937            add_header = Builder(action=['echo "$HEADER" > $TARGET',
938                                         'cat $SOURCE >> $TARGET'])
939            env.Append(BUILDERS = {'AddHeader' : add_header})
940            env['HEADER'] = '' # set default value
941       </file>
942       <file name="SConstruct">
943         env=Environment(tools=['default', TOOL_ADD_HEADER], HEADER="=====")
944         env.AddHeader('tgt', 'src')
945       </file>
946       <file name="src">
947         hi there
948       </file>
949     </scons_example>
950
951     <para>
952
953     and a &SConstruct; like this:
954
955     </para>
956
957     <sconstruct>
958         # Use TOOL_ADD_HEADER from site_scons/site_init.py
959         env=Environment(tools=['default', TOOL_ADD_HEADER], HEADER="=====")
960         env.AddHeader('tgt', 'src')
961     </sconstruct>
962
963     <para>
964
965       The <function>TOOL_ADD_HEADER</function> tool method will be
966       called to add the <function>AddHeader</function> tool to the
967       environment.
968
969     </para>
970
971     <!-- 
972     <scons_output example="site1" os="posix">
973        <scons_output_command>scons -Q</scons_output_command>
974     </scons_output>
975     -->
976
977     <para>
978       Similarly, a more full-fledged tool with
979       <function>exists()</function> and <function>generate()</function>
980       methods can be installed in
981       <filename>site_scons/site_tools/toolname.py</filename>.  Since
982       <filename>site_scons/site_tools</filename> is automatically added
983       to the head of the tool search path, any tool found there will be
984       available to all environments.  Furthermore, a tool found there
985       will override a built-in tool of the same name, so if you need to
986       change the behavior of a built-in tool, site_scons gives you the
987       hook you need.
988     </para>
989
990     <para>
991       Many people have a library of utility Python functions they'd like
992       to include in &SConscript;s; just put that module in
993       <filename>site_scons/my_utils.py</filename> or any valid Python module name of your
994       choice.  For instance you can do something like this in
995       <filename>site_scons/my_utils.py</filename> to add
996       <function>build_id</function> and <function>MakeWorkDir</function>
997       functions:
998     </para>
999       
1000     <scons_example name="site2">
1001       <file name="site_scons/my_utils.py" printme=1>
1002         from SCons.Script import *   # for Execute and Mkdir
1003         def build_id():
1004            """Return a build ID (stub version)"""
1005            return "100"
1006         def MakeWorkDir(workdir):
1007            """Create the specified dir immediately"""
1008            Execute(Mkdir(workdir))
1009       </file>
1010       <file name="SConscript">
1011         import my_utils
1012         MakeWorkDir('/tmp/work')
1013         print "build_id=" + my_utils.build_id()
1014       </file>
1015     </scons_example>
1016
1017     <para>
1018
1019     And then in your &SConscript; or any sub-&SConscript; anywhere in
1020     your build, you can import <filename>my_utils</filename> and use it:
1021
1022     </para>
1023
1024     <sconstruct>
1025         import my_utils
1026         print "build_id=" + my_utils.build_id()
1027         my_utils.MakeWorkDir('/tmp/work')
1028     </sconstruct>
1029
1030     <para>
1031       Note that although you can put this library in
1032       <filename>site_scons/site_init.py</filename>,
1033       it is no better there than <filename>site_scons/my_utils.py</filename>
1034       since you still have to import that module into your &SConscript;.
1035       Also note that in order to refer to objects in the SCons namespace
1036       such as &Environment; or &Mkdir; or &Execute; in any file other
1037       than a &SConstruct; or &SConscript; you always need to do
1038     </para>
1039     <sconstruct>
1040         from SCons.Script import *
1041     </sconstruct>
1042
1043     <para>
1044       This is true in modules in <filename>site_scons</filename> such as
1045       <filename>site_scons/site_init.py</filename> as well.
1046     </para>
1047
1048     <para>
1049
1050       If you have a machine-wide site dir you'd like to use instead of
1051       <filename>./site_scons</filename>, use the
1052       <literal>--site-dir</literal> option to point to your dir.
1053       <filename>site_init.py</filename> and
1054       <filename>site_tools</filename> will be located under that dir.
1055       To avoid using a <filename>site_scons</filename> dir at all, even
1056       if it exists, use the <literal>--no-site-dir</literal> option.
1057
1058     </para>
1059
1060   </section>
1061
1062
1063   <!--
1064
1065   <section>
1066   <title>Builders That Use Other Builders</title>
1067
1068     <para>
1069
1070     XXX para
1071
1072     </para>
1073
1074     <scons_example name="ex8">
1075        <file name="SConstruct" printme="1">
1076        env = Environment()
1077        #env.SourceCode('.', env.BitKeeper('my_command'))
1078        env.Program('hello.c')
1079        </file>
1080        <file name="hello.c">
1081        hello.c
1082        </file>
1083     </scons_example>
1084
1085     <scons_output example="ex8">
1086       <scons_output_command>scons -Q</scons_output_command>
1087     </scons_output>
1088
1089   </section>
1090
1091   -->