http://scons.tigris.org/issues/show_bug.cgi?id=2345
[scons.git] / doc / user / factories.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   <para>
27
28   &SCons; provides a number of platform-independent functions,
29   called <literal>factories</literal>,
30   that perform common file system manipulations
31   like copying, moving or deleting files and directories,
32   or making directories.
33   These functions are <literal>factories</literal>
34   because they don't perform the action
35   at the time they're called,
36   they each return an &Action; object
37   that can be executed at the appropriate time.
38
39   </para>
40
41   <section>
42   <title>Copying Files or Directories:  The &Copy; Factory</title>
43
44     <para>
45
46     Suppose you want to arrange to make a copy of a file,
47     and don't have a suitable pre-existing builder.
48     <footnote>
49     <para>
50     Unfortunately, in the early days of SCons design,
51     we used the name &Copy; for the function that
52     returns a copy of the environment,
53     otherwise that would be the logical choice for
54     a Builder that copies a file or directory tree
55     to a target location.
56     </para>
57     </footnote>
58     One way would be to use the &Copy; action factory
59     in conjunction with the &Command; builder:
60
61     </para>
62
63     <scons_example name="Copy1">
64       <file name="SConstruct" printme="1">
65         Command("file.out", "file.in", Copy("$TARGET", "$SOURCE"))
66       </file>
67       <file name="file.in">file.in</file>
68     </scons_example>
69
70     <para>
71
72     Notice that the action returned by the &Copy; factory
73     will expand the &cv-link-TARGET; and &cv-link-SOURCE; strings
74     at the time &file_out; is built,
75     and that the order of the arguments
76     is the same as that of a builder itself--that is,
77     target first, followed by source:
78
79     </para>
80
81     <scons_output example="Copy1">
82        <scons_output_command>scons -Q</scons_output_command>
83     </scons_output>
84
85     <para>
86
87     You can, of course, name a file explicitly
88     instead of using &cv-TARGET; or &cv-SOURCE;:
89
90     </para>
91
92     <scons_example name="Copy2">
93       <file name="SConstruct" printme="1">
94       Command("file.out", [], Copy("$TARGET", "file.in"))
95       </file>
96       <file name="file.in">file.in</file>
97     </scons_example>
98
99     <para>
100
101     Which executes as:
102
103     </para>
104
105     <scons_output example="Copy2">
106       <scons_output_command>scons -Q</scons_output_command>
107     </scons_output>
108
109     <para>
110
111     The usefulness of the &Copy; factory
112     becomes more apparent when
113     you use it in a list of actions
114     passed to the &Command; builder.
115     For example, suppose you needed to run a
116     file through a utility that only modifies files in-place,
117     and can't "pipe" input to output.
118     One solution is to copy the source file
119     to a temporary file name,
120     run the utility,
121     and then copy the modified temporary file to the target,
122     which the &Copy; factory makes extremely easy:
123
124     </para>
125
126     <scons_example name="Copy3">
127       <file name="S" printme="1">
128       Command("file.out", "file.in",
129               [
130                 Copy("tempfile", "$SOURCE"),
131                 "modify tempfile",
132                 Copy("$TARGET", "tempfile"),
133               ])
134       </file>
135       <file name="SConstruct">
136       env = DefaultEnvironment()
137       import os
138       env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd()
139       SConscript('S')
140       </file>
141       <file name="file.in">file.in</file>
142       <file name="modify" chmod="0755">
143       touch $*
144       </file>
145     </scons_example>
146
147     <para>
148
149     The output then looks like:
150
151     </para>
152
153     <scons_output example="Copy3">
154       <scons_output_command>scons -Q</scons_output_command>
155     </scons_output>
156
157   </section>
158
159   <section>
160   <title>Deleting Files or Directories:  The &Delete; Factory</title>
161
162     <para>
163
164     If you need to delete a file,
165     then the &Delete; factory
166     can be used in much the same way as
167     the &Copy; factory.
168     For example, if we want to make sure that
169     the temporary file
170     in our last example doesn't exist before
171     we copy to it,
172     we could add &Delete; to the beginning
173     of the command list:
174
175     </para>
176
177     <scons_example name="Delete1">
178       <file name="S" printme="1">
179       Command("file.out", "file.in",
180               [
181                 Delete("tempfile"),
182                 Copy("tempfile", "$SOURCE"),
183                 "modify tempfile",
184                 Copy("$TARGET", "tempfile"),
185               ])
186       </file>
187       <file name="SConstruct">
188       env = DefaultEnvironment()
189       import os
190       env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd()
191       SConscript('S')
192       </file>
193       <file name="file.in">file.in</file>
194       <file name="modify" chmod="0755">
195       touch $*
196       </file>
197     </scons_example>
198
199     <para>
200
201     Which then executes as follows:
202
203     </para>
204
205     <scons_output example="Delete1">
206       <scons_output_command>scons -Q</scons_output_command>
207     </scons_output>
208
209     <para>
210
211     Of course, like all of these &Action; factories,
212     the &Delete factory also expands
213     &cv-link-TARGET; and &cv-link-SOURCE; variables appropriately.
214     For example:
215
216     </para>
217
218     <scons_example name="Delete2">
219       <file name="SConstruct" printme="1">
220       Command("file.out", "file.in",
221               [
222                 Delete("$TARGET"),
223                 Copy("$TARGET", "$SOURCE")
224               ])
225       </file>
226       <file name="file.in">file.in</file>
227     </scons_example>
228
229     <para>
230
231     Executes as:
232
233     </para>
234
235     <scons_output example="Delete2">
236       <scons_output_command>scons -Q</scons_output_command>
237     </scons_output>
238
239     <para>
240
241     Note, however, that you typically don't need to
242     call the &Delete; factory explicitly in this way;
243     by default, &SCons; deletes its target(s)
244     for you before executing any action.
245
246     </para>
247
248     <para>
249
250     One word of caution about using the &Delete; factory:
251     it has the same variable expansions available
252     as any other factory, including the &cv-SOURCE; variable.
253     Specifying <literal>Delete("$SOURCE")</literal>
254     is not something you usually want to do!
255
256     </para>
257
258   </section>
259
260   <section>
261   <title>Moving (Renaming) Files or Directories:  The &Move; Factory</title>
262
263     <para>
264
265     The &Move; factory
266     allows you to rename a file or directory.
267     For example, if we don't want to copy the temporary file,
268     we could use:
269
270     </para>
271
272     <scons_example name="Move">
273       <file name="S" printme="1">
274       Command("file.out", "file.in",
275               [
276                 Copy("tempfile", "$SOURCE"),
277                 "modify tempfile",
278                 Move("$TARGET", "tempfile"),
279               ])
280       </file>
281       <file name="SConstruct">
282       env = DefaultEnvironment()
283       import os
284       env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd()
285       SConscript('S')
286       </file>
287       <file name="file.in">file.in</file>
288       <file name="modify" chmod="0755">
289       touch $*
290       </file>
291     </scons_example>
292
293     <para>
294
295     Which would execute as:
296
297     </para>
298
299     <scons_output example="Move">
300       <scons_output_command>scons -Q</scons_output_command>
301     </scons_output>
302
303   </section>
304
305   <section>
306   <title>Updating the Modification Time of a File:  The &Touch; Factory</title>
307
308     <para>
309
310     If you just need to update the
311     recorded modification time for a file,
312     use the &Touch; factory:
313
314     </para>
315
316     <scons_example name="Touch">
317       <file name="S" printme="1">
318       Command("file.out", "file.in",
319               [
320                 Copy("$TARGET", "$SOURCE"),
321                 Touch("$TARGET"),
322               ])
323       </file>
324       <file name="SConstruct">
325       env = DefaultEnvironment()
326       import os
327       env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd()
328       SConscript('S')
329       </file>
330       <file name="file.in">file.in</file>
331     </scons_example>
332
333     <para>
334
335     Which executes as:
336
337     </para>
338
339     <scons_output example="Touch">
340       <scons_output_command>scons -Q</scons_output_command>
341     </scons_output>
342
343   </section>
344
345   <section>
346   <title>Creating a Directory:  The &Mkdir; Factory</title>
347
348     <para>
349
350     If you need to create a directory,
351     use the &Mkdir; factory.
352     For example, if we need to process
353     a file in a temporary directory
354     in which the processing tool
355     will create other files that we don't care about, 
356     you could use:
357
358     </para>
359
360     <scons_example name="Mkdir">
361       <file name="S" printme="1">
362       Command("file.out", "file.in",
363               [
364                 Delete("tempdir"),
365                 Mkdir("tempdir"),
366                 Copy("tempdir/${SOURCE.file}", "$SOURCE"),
367                 "process tempdir",
368                 Move("$TARGET", "tempdir/output_file"),
369                 Delete("tempdir"),
370               ])
371       </file>
372       <file name="SConstruct">
373       env = DefaultEnvironment()
374       import os
375       env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd()
376       SConscript('S')
377       </file>
378       <file name="file.in">file.in</file>
379       <file name="process" chmod="0755">
380       touch $*
381       </file>
382     </scons_example>
383
384     <para>
385
386     Which executes as:
387
388     </para>
389
390     <scons_output example="Mkdir">
391       <scons_output_command>scons -Q</scons_output_command>
392     </scons_output>
393
394   </section>
395
396   <section>
397   <title>Changing File or Directory Permissions:  The &Chmod; Factory</title>
398
399     <para>
400
401     To change permissions on a file or directory,
402     use the &Chmod; factory.
403     The permission argument uses POSIX-style
404     permission bits and should typically
405     be expressed as an octal,
406     not decimal, number:
407
408     </para>
409
410     <scons_example name="Chmod">
411       <file name="SConstruct" printme="1">
412       Command("file.out", "file.in",
413               [
414                 Copy("$TARGET", "$SOURCE"),
415                 Chmod("$TARGET", 0755),
416               ])
417       </file>
418       <file name="file.in">file.in</file>
419     </scons_example>
420
421     <para>
422
423     Which executes:
424
425     </para>
426
427     <scons_output example="Chmod">
428       <scons_output_command>scons -Q</scons_output_command>
429     </scons_output>
430
431   </section>
432
433   <section>
434   <title>Executing an action immediately:  the &Execute; Function</title>
435
436     <para>
437
438     We've been showing you how to use &Action; factories
439     in the &Command; function.
440     You can also execute an &Action; returned by a factory
441     (or actually, any &Action;)
442     at the time the &SConscript; file is read
443     by using the &Execute; function.
444     For example, if we need to make sure that
445     a directory exists before we build any targets,
446
447     </para>
448
449     <scons_example name="Execute">
450       <file name="SConstruct" printme="1">
451       Execute(Mkdir('__ROOT__/tmp/my_temp_directory'))
452       </file>
453     </scons_example>
454
455     <para>
456
457     Notice that this will
458     create the directory while
459     the &SConscript; file is being read:
460
461     </para>
462
463     <scons_output example="Execute">
464       <scons_output_command>scons</scons_output_command>
465     </scons_output>
466
467     <para>
468
469     If you're familiar with Python,
470     you may wonder why you would want to use this
471     instead of just calling the native Python
472     <function>os.mkdir()</function> function.
473     The advantage here is that the &Mkdir;
474     action will behave appropriately if the user
475     specifies the &SCons; <option>-n</option> or
476     <option>-q</option> options--that is,
477     it will print the action but not actually
478     make the directory when <option>-n</option> is specified,
479     or make the directory but not print the action
480     when <option>-q</option> is specified.
481
482     </para>
483
484     <para>
485
486     The &Execute; function returns the exit status
487     or return value of the underlying action being executed.
488     It will also print an error message if the action
489     fails and returns a non-zero value.
490     &SCons; will <emphasis>not</emphasis>, however,
491     actually stop the build if the action fails.
492     If you want the build to stop
493     in response to a failure in an action called by &Execute;,
494     you must do so by explicitly
495     checking the return value
496     and calling the &Exit; function
497     (or a Python equivalent):
498
499     </para>
500
501     <sconstruct>
502     if Execute(Mkdir('__ROOT__/tmp/my_temp_directory')):
503         # A problem occurred while making the temp directory.
504         Exit(1)
505     </sconstruct>
506
507   </section>