diff options
Diffstat (limited to 'doc/user/misc.in')
-rw-r--r-- | doc/user/misc.in | 606 |
1 files changed, 606 insertions, 0 deletions
diff --git a/doc/user/misc.in b/doc/user/misc.in new file mode 100644 index 0000000..6679134 --- /dev/null +++ b/doc/user/misc.in @@ -0,0 +1,606 @@ +<!-- + + 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; supports a lot of additional functionality + that doesn't readily fit into the other chapters. + + </para> + + <section> + <title>Verifying the Python Version: the &EnsurePythonVersion; Function</title> + + <para> + + Although the &SCons; code itself will run + on any Python version 1.5.2 or later, + you are perfectly free to make use of + Python syntax and modules from more modern versions + (for example, Python 2.4 or 2.5) + when writing your &SConscript; files + or your own local modules. + If you do this, it's usually helpful to + configure &SCons; to exit gracefully with an error message + if it's being run with a version of Python + that simply won't work with your code. + This is especially true if you're going to use &SCons; + to build source code that you plan to distribute publicly, + where you can't be sure of the Python version + that an anonymous remote user might use + to try to build your software. + + </para> + + <para> + + &SCons; provides an &EnsurePythonVersion; function for this. + You simply pass it the major and minor versions + numbers of the version of Python you require: + + </para> + + <!-- + + TODO: Figure out how to generate the error message + regardless of executing Python version by faking out + the infrastructure in some way. + + <scons_example name="EnsurePythonVersion"> + <file name="SConstruct" printme="1"> + EnsurePythonVersion(2, 5) + </file> + </scons_example> + + --> + + <sconstruct> + EnsurePythonVersion(2, 5) + </sconstruct> + + <para> + + And then &SCons will exit with the following error + message when a user runs it with an unsupported + earlier version of Python: + + </para> + + <!-- + + TODO: Figure out how to generate the error message + regardless of executing Python version by faking out + the infrastructure in some way. + + <scons_output example="EnsurePythonVersion"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + Python 2.5 or greater required, but you have Python 2.3.6 + </screen> + + </section> + + <section> + <title>Verifying the SCons Version: the &EnsureSConsVersion; Function</title> + + <para> + + You may, of course, write your &SConscript; files + to use features that were only added in + recent versions of &SCons;. + When you publicly distribute software that is built using &SCons;, + it's helpful to have &SCons; + verify the version being used and + exit gracefully with an error message + if the user's version of &SCons; won't work + with your &SConscript; files. + &SCons; provides an &EnsureSConsVersion; function + that verifies the version of &SCons; + in the same + the &EnsurePythonVersion; function + verifies the version of Python, + by passing in the major and minor versions + numbers of the version of SCons you require: + + </para> + + <!-- + + TODO: Figure out how to generate the error message + regardless of executing SCons version by faking out + the infrastructure in some way. + + <scons_example name="EnsureSConsVersion"> + <file name="SConstruct" printme="1"> + EnsureSConsVersion(1, 0) + </file> + </scons_example> + + --> + + <sconstruct> + EnsureSConsVersion(1, 0) + </sconstruct> + + <para> + + And then &SCons will exit with the following error + message when a user runs it with an unsupported + earlier version of &SCons;: + + </para> + + <!-- + + TODO: Figure out how to generate the error message + regardless of executing SCons version by faking out + the infrastructure in some way. + + <scons_output example="EnsureSConsVersion"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + SCons 1.0 or greater required, but you have SCons 0.98.5 + </screen> + + </section> + + <section> + <title>Explicitly Terminating &SCons; While Reading &SConscript; Files: the &Exit; Function</title> + + <para> + + &SCons; supports an &Exit; function + which can be used to terminate &SCons; + while reading the &SConscript; files, + usually because you've detected a condition + under which it doesn't make sense to proceed: + + </para> + + <scons_example name="Exit"> + <file name="SConstruct" printme="1"> + if ARGUMENTS.get('FUTURE'): + print "The FUTURE option is not supported yet!" + Exit(2) + env = Environment() + env.Program('hello.c') + </file> + <file name="hello.c"> + hello.c + </file> + </scons_example> + + <scons_output example="Exit"> + <scons_output_command>scons -Q FUTURE=1</scons_output_command> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + The &Exit; function takes as an argument + the (numeric) exit status that you want &SCons; to exit with. + If you don't specify a value, + the default is to exit with <literal>0</literal>, + which indicates successful execution. + + </para> + + <para> + + Note that the &Exit; function + is equivalent to calling the Python + <function>sys.exit</function> function + (which the it actually calls), + but because &Exit; is a &SCons; function, + you don't have to import the Python + <literal>sys</literal> module to use it. + + </para> + + </section> + + <section> + <title>Searching for Files: the &FindFile; Function</title> + + <para> + + The &FindFile; function searches for a file in a list of directories. + If there is only one directory, it can be given as a simple string. + The function returns a File node if a matching file exists, + or None if no file is found. + (See the documentation for the &Glob; function for an alternative way + of searching for entries in a directory.) + + </para> + + <scons_example name="FindFile1a"> + <file name="SConstruct" printme="1"> + # one directory + print FindFile('missing', '.') + t = FindFile('exists', '.') + print t.__class__, t + </file> + <file name="exists"> + exists + </file> + </scons_example> + + <scons_output example="FindFile1a" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <scons_example name="FindFile1b"> + <file name="SConstruct" printme="1"> + # several directories + includes = [ '.', 'include', 'src/include'] + headers = [ 'nonesuch.h', 'config.h', 'private.h', 'dist.h'] + for hdr in headers: + print '%-12s' % ('%s:' % hdr), FindFile(hdr, includes) + </file> + <file name="config.h"> + exists + </file> + <directory name="src"></directory> + <directory name="src/include"></directory> + </file> + <file name="src/include/private.h"> + exists + <directory name="include"></directory> + </file> + <file name="include/dist.h"> + exists + </scons_example> + + <scons_output example="FindFile1b" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <!-- The man page says this should work, but it fails. + <para> + + If the 'file' parameter is a list of files, + a list of File nodes is returned. + + </para> + + <scons_example name="FindFile1c"> + <file name="SConstruct" printme="1"> + # several directories + includes = [ '.', 'include', 'src/include'] + headers = [ 'nonesuch.h', 'config.h', 'private.h', 'dist.h'] + print FindFile(headers, includes) + </file> + <file name="config.h"> + exists + </file> + <directory name="src"></directory> + <directory name="src/include"></directory> + </file> + <file name="src/include/private.h"> + exists + <directory name="include"></directory> + </file> + <file name="include/dist.h"> + exists + </scons_example> + + <scons_output example="FindFile1c" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + --> + + <para> + + If the file exists in more than one directory, + only the first occurrence is returned. + + </para> + + <scons_example name="FindFile1d"> + <file name="SConstruct" printme="1"> + print FindFile('multiple', ['sub1', 'sub2', 'sub3']) + print FindFile('multiple', ['sub2', 'sub3', 'sub1']) + print FindFile('multiple', ['sub3', 'sub1', 'sub2']) + </file> + <directory name="sub1"></directory> + <file name="sub1/multiple"> + exists + </file> + <directory name="sub2"></directory> + <file name="sub2/multiple"> + exists + </file> + <directory name="sub3"></directory> + <file name="sub3/multiple"> + exists + </file> + </scons_example> + + <scons_output example="FindFile1d" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <!-- file may be a list of file names or a single file name. --> + + <para> + + In addition to existing files, &FindFile; will also find derived files + (that is, non-leaf files) that haven't been built yet. + (Leaf files should already exist, or the build will fail!) + + </para> + + <scons_example name="FindFile2"> + <file name="SConstruct" printme="1"> + # Neither file exists, so build will fail + Command('derived', 'leaf', 'cat >$TARGET $SOURCE') + print FindFile('leaf', '.') + print FindFile('derived', '.') + </file> + </scons_example> + + <scons_output example="FindFile2" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <scons_example name="FindFile2"> + <file name="SConstruct" printme="1"> + # Only 'leaf' exists + Command('derived', 'leaf', 'cat >$TARGET $SOURCE') + print FindFile('leaf', '.') + print FindFile('derived', '.') + </file> + <file name="leaf"> + leaf + </file> + </scons_example> + + <scons_output example="FindFile2" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + If a source file exists, &FindFile; will correctly return the name + in the build directory. + + </para> + + <scons_example name="FindFile3"> + <file name="SConstruct" printme="1"> + # Only 'src/leaf' exists + VariantDir('build', 'src') + print FindFile('leaf', 'build') + </file> + <directory name="src"></directory> + <file name="src/leaf"> + leaf + </file> + </scons_example> + + <scons_output example="FindFile3" os="posix"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + </section> + + <section> + <title>Handling Nested Lists: the &Flatten; Function</title> + + <para> + + &SCons; supports a &Flatten; function + which takes an input Python sequence + (list or tuple) + and returns a flattened list + containing just the individual elements of + the sequence. + This can be handy when trying to examine + a list composed of the lists + returned by calls to various Builders. + For example, you might collect + object files built in different ways + into one call to the &Program; Builder + by just enclosing them in a list, as follows: + + </para> + + <scons_example name="Flatten1"> + <file name="SConstruct" printme="1"> + objects = [ + Object('prog1.c'), + Object('prog2.c', CCFLAGS='-DFOO'), + ] + Program(objects) + </file> + <file name="prog1.c"> + prog1.c + </file> + <file name="prog2.c"> + prog2.c + </file> + </scons_example> + + <para> + + Because the Builder calls in &SCons; + flatten their input lists, + this works just fine to build the program: + + </para> + + <scons_output example="Flatten1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + But if you were debugging your build + and wanted to print the absolute path + of each object file in the + <varname>objects</varname> list, + you might try the following simple approach, + trying to print each Node's + <literal>abspath</literal> + attribute: + + </para> + + <scons_example name="Flatten2"> + <file name="SConstruct" printme="1"> + objects = [ + Object('prog1.c'), + Object('prog2.c', CCFLAGS='-DFOO'), + ] + Program(objects) + + for object_file in objects: + print object_file.abspath + </file> + <file name="prog1.c"> + prog1.c + </file> + <file name="prog2.c"> + prog2.c + </file> + </scons_example> + + <para> + + This does not work as expected + because each call to <function>str</function> + is operating an embedded list returned by + each &Object; call, + not on the underlying Nodes within those lists: + + </para> + + <scons_output example="Flatten2"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + The solution is to use the &Flatten; function + so that you can pass each Node to + the <function>str</function> separately: + + </para> + + <scons_example name="Flatten3"> + <file name="SConstruct" printme="1"> + objects = [ + Object('prog1.c'), + Object('prog2.c', CCFLAGS='-DFOO'), + ] + Program(objects) + + for object_file in Flatten(objects): + print object_file.abspath + </file> + <file name="prog1.c"> + prog1.c + </file> + <file name="prog2.c"> + prog2.c + </file> + </scons_example> + + <!-- + + TODO: can't use this now because it displays the temporary path name + + <scons_output example="Flatten3"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <screen> + % <userinput>scons -Q</userinput> + /home/me/project/prog1.o + /home/me/project/prog2.o + cc -o prog1.o -c prog1.c + cc -o prog2.o -c -DFOO prog2.c + cc -o prog1 prog1.o prog2.o + </screen> + + </section> + + <section> + <title>Finding the Invocation Directory: the &GetLaunchDir; Function</title> + + <para> + + If you need to find the directory from + which the user invoked the &scons; command, + you can use the &GetLaunchDir; function: + + </para> + + <sconstruct> + env = Environment( + LAUNCHDIR = GetLaunchDir(), + ) + env.Command('directory_build_info', + '$LAUNCHDIR/build_info' + Copy('$TARGET', '$SOURCE')) + </sconstruct> + + <para> + + Because &SCons; is usually invoked from the top-level + directory in which the &SConstruct; file lives, + the Python <function>os.getcwd()</function> + is often equivalent. + However, the &SCons; + <literal>-u</literal>, + <literal>-U</literal> + and + <literal>-D</literal> + command-line options, + when invoked from a subdirectory, + will cause &SCons; to change to the directory + in which the &SConstruct; file is found. + When those options are used, + &GetLaunchDir; will still return the path to the + user's invoking subdirectory, + allowing the &SConscript; configuration + to still get at configuration (or other) files + from the originating directory. + + </para> + + </section> |