mirror of
https://github.com/Relintai/scons_gd.git
synced 2025-02-06 16:25:59 +01:00
682 lines
19 KiB
XML
682 lines
19 KiB
XML
<?xml version='1.0'?>
|
|
<!DOCTYPE sconsdoc [
|
|
<!ENTITY % scons SYSTEM "../scons.mod">
|
|
%scons;
|
|
|
|
<!ENTITY % builders-mod SYSTEM "../generated/builders.mod">
|
|
%builders-mod;
|
|
<!ENTITY % functions-mod SYSTEM "../generated/functions.mod">
|
|
%functions-mod;
|
|
<!ENTITY % tools-mod SYSTEM "../generated/tools.mod">
|
|
%tools-mod;
|
|
<!ENTITY % variables-mod SYSTEM "../generated/variables.mod">
|
|
%variables-mod;
|
|
]>
|
|
|
|
<chapter id="chap-misc"
|
|
xmlns="http://www.scons.org/dbxsd/v1.0"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
|
|
<title>Miscellaneous Functionality</title>
|
|
|
|
<!--
|
|
|
|
__COPYRIGHT__
|
|
|
|
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 2.x Python version 2.7 or later,
|
|
you are perfectly free to make use of
|
|
Python syntax and modules from later versions
|
|
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="misc_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="misc_EnsurePythonVersion" suffix="1">
|
|
<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="misc_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="misc_EnsureSConsVersion" suffix="1">
|
|
<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="misc_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="misc_Exit" suffix="1">
|
|
<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 &f-link-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 &f-link-Glob; function for an alternative way
|
|
of searching for entries in a directory.)
|
|
|
|
</para>
|
|
|
|
<scons_example name="misc_FindFile1a">
|
|
<file name="SConstruct" printme="1">
|
|
# one directory
|
|
print("%s"%FindFile('missing', '.'))
|
|
t = FindFile('exists', '.')
|
|
print("%s %s"%(t.__class__, t))
|
|
</file>
|
|
<file name="exists">
|
|
exists
|
|
</file>
|
|
</scons_example>
|
|
|
|
<scons_output example="misc_FindFile1a" os="posix" suffix="1">
|
|
<scons_output_command>scons -Q</scons_output_command>
|
|
</scons_output>
|
|
|
|
<scons_example name="misc_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 name="src/include/private.h">
|
|
exists
|
|
</file>
|
|
<directory name="include"></directory>
|
|
<file name="include/dist.h">
|
|
exists
|
|
</file>
|
|
</scons_example>
|
|
|
|
<scons_output example="misc_FindFile1b" os="posix" suffix="1">
|
|
<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="misc_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="misc_FindFile1c" os="posix" suffix="1">
|
|
<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="misc_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="misc_FindFile1d" os="posix" suffix="1">
|
|
<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="misc_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="misc_FindFile2" os="posix" suffix="1">
|
|
<scons_output_command>scons -Q</scons_output_command>
|
|
</scons_output>
|
|
|
|
<scons_example name="misc_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="misc_FindFile2" os="posix" suffix="2">
|
|
<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="misc_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="misc_FindFile3" os="posix" suffix="1">
|
|
<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="misc_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="misc_Flatten1" suffix="1">
|
|
<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="misc_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="misc_Flatten2" suffix="1">
|
|
<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="misc_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="misc_Flatten3" suffix="1">
|
|
<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>
|
|
|
|
<!-- Former unpublished chapter now included as a section here: -->
|
|
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="sideeffect.xml"/>
|
|
|
|
<section>
|
|
<title>Virtual environments (virtualenvs)</title>
|
|
|
|
<para>
|
|
|
|
Virtualenv is a tool to create isolated Python environments.
|
|
A python application (such as SCons) may be executed within
|
|
an activated virtualenv. The activation of virtualenv modifies
|
|
current environment by defining some virtualenv-specific variables
|
|
and modifying search PATH, such that executables installed within
|
|
virtualenv's home directory are preferred over the ones installed
|
|
outside of it.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Normally, SCons uses hard-coded PATH when searching for external
|
|
executables, so it always picks-up executables from these pre-defined
|
|
locations. This applies also to python interpreter, which is invoked
|
|
by some custom SCons tools or test suites. This means, when running
|
|
SCons in a virtualenv, an eventual invocation of python interpreter from
|
|
SCons script will most probably jump out of virtualenv and execute
|
|
python executable found in hard-coded SCons PATH, not the one which is
|
|
executing SCons. Some users may consider this as an inconsistency.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
This issue may be overcome by using the
|
|
<option>--enable-virtualenv</option>
|
|
option. The option automatically imports virtualenv-related environment
|
|
variables to all created construction environment <literal>env['ENV']</literal>,
|
|
and modifies SCons PATH appropriately to prefer virtualenv's executables.
|
|
Setting environment variable <envar>SCONS_ENABLE_VIRTUALENV=1</envar>
|
|
will have same effect. If virtualenv support is enabled system-vide
|
|
by the environment variable, it may be suppressed with the
|
|
<option>--ignore-virtualenv</option> option.
|
|
</para>
|
|
|
|
<para>
|
|
Inside of &SConscript;, a global function <literal>Virtualenv</literal> is
|
|
available. It returns a path to virtualenv's home directory, or
|
|
<literal>None</literal> if &scons; is not running from virtualenv. Note
|
|
that this function returns a path even if &scons; is run from an
|
|
unactivated virtualenv.
|
|
</para>
|
|
|
|
</section>
|
|
|
|
</chapter>
|