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