Merged revisions 2454-2525 via svnmerge from
[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-link-TARGET; and &cv-link-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-link-TARGET; and &cv-link-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 use:
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("$TARGET", "$SOURCE"),
302                 Touch("$TARGET"),
303               ])
304       </file>
305       <file name="SConstruct">
306       env = DefaultEnvironment()
307       import os
308       env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd()
309       SConscript('S')
310       </file>
311       <file name="file.in">file.in</file>
312     </scons_example>
313
314     <para>
315
316     Which executes as:
317
318     </para>
319
320     <scons_output example="Touch">
321       <scons_output_command>scons -Q</scons_output_command>
322     </scons_output>
323
324   </section>
325
326   <section>
327   <title>Creating a Directory:  The &Mkdir; Factory</title>
328
329     <para>
330
331     If you need to create a directory,
332     use the &Mkdir; factory.
333     For example, if we need to process
334     a file in a temporary directory
335     in which the processing tool
336     will create other files that we don't care about, 
337     you could use:
338
339     </para>
340
341     <scons_example name="Mkdir">
342       <file name="S" printme="1">
343       Command("file.out", "file.in",
344               [
345                 Delete("tempdir"),
346                 Mkdir("tempdir"),
347                 Copy("tempdir/${SOURCE.file}", "$SOURCE"),
348                 "process tempdir",
349                 Move("$TARGET", "tempdir/output_file"),
350                 Delete("tempdir"),
351               ])
352       </file>
353       <file name="SConstruct">
354       env = DefaultEnvironment()
355       import os
356       env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd()
357       SConscript('S')
358       </file>
359       <file name="file.in">file.in</file>
360       <file name="process" chmod="0755">
361       touch $*
362       </file>
363     </scons_example>
364
365     <para>
366
367     Which executes as:
368
369     </para>
370
371     <scons_output example="Mkdir">
372       <scons_output_command>scons -Q</scons_output_command>
373     </scons_output>
374
375   </section>
376
377   <section>
378   <title>Changing File or Directory Permissions:  The &Chmod; Factory</title>
379
380     <para>
381
382     To change permissions on a file or directory,
383     use the &Chmod; factory.
384     The permission argument uses POSIX-style
385     permission bits and should typically
386     be expressed as an octal,
387     not decimal, number:
388
389     </para>
390
391     <scons_example name="Chmod">
392       <file name="SConstruct" printme="1">
393       Command("file.out", "file.in",
394               [
395                 Copy("$TARGET", "$SOURCE"),
396                 Chmod("$TARGET", 0755),
397               ])
398       </file>
399       <file name="file.in">file.in</file>
400     </scons_example>
401
402     <para>
403
404     Which executes:
405
406     </para>
407
408     <scons_output example="Chmod">
409       <scons_output_command>scons -Q</scons_output_command>
410     </scons_output>
411
412   </section>
413
414   <section>
415   <title>Executing an action immediately:  the &Execute; Function</title>
416
417     <para>
418
419     We've been showing you how to use &Action; factories
420     in the &Command; function.
421     You can also execute an &Action; returned by a factory
422     (or actually, any &Action;)
423     at the time the &SConscript; file is read
424     by wrapping it up in the &Execute; function.
425     For example, if we need to make sure that
426     a directory exists before we build any targets,
427
428
429     </para>
430
431     <scons_example name="Execute">
432       <file name="SConstruct" printme="1">
433       Execute(Mkdir('__ROOT__/tmp/my_temp_directory'))
434       </file>
435     </scons_example>
436
437     <para>
438
439     Notice that this will
440     create the directory while
441     the &SConscript; file is being read:
442
443     </para>
444
445     <scons_output example="Execute">
446       <scons_output_command>scons</scons_output_command>
447     </scons_output>
448
449     <para>
450
451     If you're familiar with Python,
452     you may wonder why you would want to use this
453     instead of just calling the native Python
454     <function>os.mkdir()</function> function.
455     The advantage here is that the &Mkdir;
456     action will behave appropriately if the user
457     specifies the &SCons; <option>-n</option> or
458     <option>-q</option> options--that is,
459     it will print the action but not actually
460     make the directory when <option>-n</option> is specified,
461     or make the directory but not print the action
462     when <option>-q</option> is specified.
463
464     </para>
465
466   </section>