diff options
Diffstat (limited to 'doc/user/factories.in')
-rw-r--r-- | doc/user/factories.in | 507 |
1 files changed, 507 insertions, 0 deletions
diff --git a/doc/user/factories.in b/doc/user/factories.in new file mode 100644 index 0000000..0cea6c4 --- /dev/null +++ b/doc/user/factories.in @@ -0,0 +1,507 @@ +<!-- + + Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + + <para> + + &SCons; provides a number of platform-independent functions, + called <literal>factories</literal>, + that perform common file system manipulations + like copying, moving or deleting files and directories, + or making directories. + These functions are <literal>factories</literal> + because they don't perform the action + at the time they're called, + they each return an &Action; object + that can be executed at the appropriate time. + + </para> + + <section> + <title>Copying Files or Directories: The &Copy; Factory</title> + + <para> + + Suppose you want to arrange to make a copy of a file, + and don't have a suitable pre-existing builder. + <footnote> + <para> + Unfortunately, in the early days of SCons design, + we used the name &Copy; for the function that + returns a copy of the environment, + otherwise that would be the logical choice for + a Builder that copies a file or directory tree + to a target location. + </para> + </footnote> + One way would be to use the &Copy; action factory + in conjunction with the &Command; builder: + + </para> + + <scons_example name="Copy1"> + <file name="SConstruct" printme="1"> + Command("file.out", "file.in", Copy("$TARGET", "$SOURCE")) + </file> + <file name="file.in">file.in</file> + </scons_example> + + <para> + + Notice that the action returned by the &Copy; factory + will expand the &cv-link-TARGET; and &cv-link-SOURCE; strings + at the time &file_out; is built, + and that the order of the arguments + is the same as that of a builder itself--that is, + target first, followed by source: + + </para> + + <scons_output example="Copy1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + You can, of course, name a file explicitly + instead of using &cv-TARGET; or &cv-SOURCE;: + + </para> + + <scons_example name="Copy2"> + <file name="SConstruct" printme="1"> + Command("file.out", [], Copy("$TARGET", "file.in")) + </file> + <file name="file.in">file.in</file> + </scons_example> + + <para> + + Which executes as: + + </para> + + <scons_output example="Copy2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + The usefulness of the &Copy; factory + becomes more apparent when + you use it in a list of actions + passed to the &Command; builder. + For example, suppose you needed to run a + file through a utility that only modifies files in-place, + and can't "pipe" input to output. + One solution is to copy the source file + to a temporary file name, + run the utility, + and then copy the modified temporary file to the target, + which the &Copy; factory makes extremely easy: + + </para> + + <scons_example name="Copy3"> + <file name="S" printme="1"> + Command("file.out", "file.in", + [ + Copy("tempfile", "$SOURCE"), + "modify tempfile", + Copy("$TARGET", "tempfile"), + ]) + </file> + <file name="SConstruct"> + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + </file> + <file name="file.in">file.in</file> + <file name="modify" chmod="0755"> + touch $* + </file> + </scons_example> + + <para> + + The output then looks like: + + </para> + + <scons_output example="Copy3"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Deleting Files or Directories: The &Delete; Factory</title> + + <para> + + If you need to delete a file, + then the &Delete; factory + can be used in much the same way as + the &Copy; factory. + For example, if we want to make sure that + the temporary file + in our last example doesn't exist before + we copy to it, + we could add &Delete; to the beginning + of the command list: + + </para> + + <scons_example name="Delete1"> + <file name="S" printme="1"> + Command("file.out", "file.in", + [ + Delete("tempfile"), + Copy("tempfile", "$SOURCE"), + "modify tempfile", + Copy("$TARGET", "tempfile"), + ]) + </file> + <file name="SConstruct"> + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + </file> + <file name="file.in">file.in</file> + <file name="modify" chmod="0755"> + touch $* + </file> + </scons_example> + + <para> + + Which then executes as follows: + + </para> + + <scons_output example="Delete1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Of course, like all of these &Action; factories, + the &Delete factory also expands + &cv-link-TARGET; and &cv-link-SOURCE; variables appropriately. + For example: + + </para> + + <scons_example name="Delete2"> + <file name="SConstruct" printme="1"> + Command("file.out", "file.in", + [ + Delete("$TARGET"), + Copy("$TARGET", "$SOURCE") + ]) + </file> + <file name="file.in">file.in</file> + </scons_example> + + <para> + + Executes as: + + </para> + + <scons_output example="Delete2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + Note, however, that you typically don't need to + call the &Delete; factory explicitly in this way; + by default, &SCons; deletes its target(s) + for you before executing any action. + + </para> + + <para> + + One word of caution about using the &Delete; factory: + it has the same variable expansions available + as any other factory, including the &cv-SOURCE; variable. + Specifying <literal>Delete("$SOURCE")</literal> + is not something you usually want to do! + + </para> + + </section> + + <section> + <title>Moving (Renaming) Files or Directories: The &Move; Factory</title> + + <para> + + The &Move; factory + allows you to rename a file or directory. + For example, if we don't want to copy the temporary file, + we could use: + + </para> + + <scons_example name="Move"> + <file name="S" printme="1"> + Command("file.out", "file.in", + [ + Copy("tempfile", "$SOURCE"), + "modify tempfile", + Move("$TARGET", "tempfile"), + ]) + </file> + <file name="SConstruct"> + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + </file> + <file name="file.in">file.in</file> + <file name="modify" chmod="0755"> + touch $* + </file> + </scons_example> + + <para> + + Which would execute as: + + </para> + + <scons_output example="Move"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Updating the Modification Time of a File: The &Touch; Factory</title> + + <para> + + If you just need to update the + recorded modification time for a file, + use the &Touch; factory: + + </para> + + <scons_example name="Touch"> + <file name="S" printme="1"> + Command("file.out", "file.in", + [ + Copy("$TARGET", "$SOURCE"), + Touch("$TARGET"), + ]) + </file> + <file name="SConstruct"> + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + </file> + <file name="file.in">file.in</file> + </scons_example> + + <para> + + Which executes as: + + </para> + + <scons_output example="Touch"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Creating a Directory: The &Mkdir; Factory</title> + + <para> + + If you need to create a directory, + use the &Mkdir; factory. + For example, if we need to process + a file in a temporary directory + in which the processing tool + will create other files that we don't care about, + you could use: + + </para> + + <scons_example name="Mkdir"> + <file name="S" printme="1"> + Command("file.out", "file.in", + [ + Delete("tempdir"), + Mkdir("tempdir"), + Copy("tempdir/${SOURCE.file}", "$SOURCE"), + "process tempdir", + Move("$TARGET", "tempdir/output_file"), + Delete("tempdir"), + ]) + </file> + <file name="SConstruct"> + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + </file> + <file name="file.in">file.in</file> + <file name="process" chmod="0755"> + touch $* + </file> + </scons_example> + + <para> + + Which executes as: + + </para> + + <scons_output example="Mkdir"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Changing File or Directory Permissions: The &Chmod; Factory</title> + + <para> + + To change permissions on a file or directory, + use the &Chmod; factory. + The permission argument uses POSIX-style + permission bits and should typically + be expressed as an octal, + not decimal, number: + + </para> + + <scons_example name="Chmod"> + <file name="SConstruct" printme="1"> + Command("file.out", "file.in", + [ + Copy("$TARGET", "$SOURCE"), + Chmod("$TARGET", 0755), + ]) + </file> + <file name="file.in">file.in</file> + </scons_example> + + <para> + + Which executes: + + </para> + + <scons_output example="Chmod"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Executing an action immediately: the &Execute; Function</title> + + <para> + + We've been showing you how to use &Action; factories + in the &Command; function. + You can also execute an &Action; returned by a factory + (or actually, any &Action;) + at the time the &SConscript; file is read + by using the &Execute; function. + For example, if we need to make sure that + a directory exists before we build any targets, + + </para> + + <scons_example name="Execute"> + <file name="SConstruct" printme="1"> + Execute(Mkdir('__ROOT__/tmp/my_temp_directory')) + </file> + </scons_example> + + <para> + + Notice that this will + create the directory while + the &SConscript; file is being read: + + </para> + + <scons_output example="Execute"> + <scons_output_command>scons</scons_output_command> + </scons_output> + + <para> + + If you're familiar with Python, + you may wonder why you would want to use this + instead of just calling the native Python + <function>os.mkdir()</function> function. + The advantage here is that the &Mkdir; + action will behave appropriately if the user + specifies the &SCons; <option>-n</option> or + <option>-q</option> options--that is, + it will print the action but not actually + make the directory when <option>-n</option> is specified, + or make the directory but not print the action + when <option>-q</option> is specified. + + </para> + + <para> + + The &Execute; function returns the exit status + or return value of the underlying action being executed. + It will also print an error message if the action + fails and returns a non-zero value. + &SCons; will <emphasis>not</emphasis>, however, + actually stop the build if the action fails. + If you want the build to stop + in response to a failure in an action called by &Execute;, + you must do so by explicitly + checking the return value + and calling the &Exit; function + (or a Python equivalent): + + </para> + + <sconstruct> + if Execute(Mkdir('__ROOT__/tmp/my_temp_directory')): + # A problem occurred while making the temp directory. + Exit(1) + </sconstruct> + + </section> |