<?xml version="1.0" encoding="UTF-8"?>
<!--
SPDX-FileCopyrightText: Copyright The SCons Foundation (https://scons.org)
SPDX-License-Identifier: MIT
SPDX-FileType: DOCUMENTATION

This file is processed by the bin/SConsDoc.py module.
-->

<!DOCTYPE reference [
<!ENTITY % version SYSTEM "../version.xml">
%version;
<!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;
]>

<reference 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">

  <referenceinfo>
    <title>SCons &buildversion;</title>
    <subtitle>MAN page</subtitle>

    <corpauthor>The SCons Development Team</corpauthor>

    <!-- adding pubdate seems superfluous when copyright year is the same
         and html rendering puts both of them at the top of the page -->
    <pubdate>Released &builddate;</pubdate>
        <copyright>
      <year>&copyright_years;</year>
      <holder>The SCons Foundation</holder>
    </copyright>

    <releaseinfo>Version &buildversion;</releaseinfo>

    <mediaobject role="cover"><imageobject><imagedata fileref="cover.jpg" format="JPG"/></imageobject></mediaobject>

  </referenceinfo>

  <title>SCons &buildversion;</title>
  <subtitle>MAN page</subtitle>

<refentry id='scons1'>
<refmeta>
<refentrytitle>SCONS</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class='source'>SCons __VERSION__</refmiscinfo>
<refmiscinfo class='manual'>SCons __VERSION__</refmiscinfo>
</refmeta>
<refnamediv id='name'>
<refname>scons</refname>
<refpurpose>a software construction tool</refpurpose>
</refnamediv>
<!-- body begins here -->
<refsynopsisdiv id='synopsis'>
<cmdsynopsis>
  <command>scons</command>
  <arg choice='opt' rep='repeat'><replaceable>options</replaceable></arg>
  <arg choice='opt' rep='repeat'><replaceable>name</replaceable>=<replaceable>val</replaceable></arg>
  <arg choice='opt' rep='repeat'><replaceable>targets</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>


<refsect1 id='description'>
<title>DESCRIPTION</title>
<para>
&SCons; is an extensible open source build system that
orchestrates the construction of software
(and other tangible products such as documentation files)
by determining which
component pieces must be built or rebuilt and invoking the necessary
commands to build them.
&SCons; offers many features to improve developer productivity
such as parallel builds, caching of build artifacts,
automatic dependency scanning,
and a database of information about previous builds so
details do not have to be recalculated each run.
</para>

<para>&scons; requires &Python; 3.7 or later to run;
there should be no other dependencies or requirements,
unless the experimental Ninja tool is used (requires the ninja package).
</para>
<para>
<emphasis>Changed in version 4.3.0:</emphasis>
support for &Python; 3.5 is removed.
The CPython project retired 3.5 in Sept 2020:
<ulink url="https://peps.python.org/pep-0478"/>.
</para>
<para>
<emphasis>Changed in version 4.9.0:</emphasis>
support for &Python; 3.6 is removed.
The CPython project retired 3.6 in Sept 2021:
<ulink url="https://peps.python.org/pep-0494"/>.
</para>

<para>
You set up an &SCons; build by writing a script
that describes things to build (<firstterm>targets</firstterm>), and,
if necessary, the rules to build those files (<firstterm>actions</firstterm>).
&SCons; comes with a collection of <firstterm>Builder</firstterm> methods
which supply premade Actions for building many common software components
such as executable programs, object files and libraries,
so that for many software projects,
only the targets and input files (<firstterm>sources</firstterm>)
need be specified in a call to a builder.
</para>

<para>
&SCons; operates at a level of abstraction above that of pure filenames.
For example if you specify a shared library target named "foo",
&SCons; keeps track of the actual operating system dependent filename
(such as <filename>libfoo.so</filename> on a GNU/Linux system
and <filename>foo.dll</filename> on Windows),
and gives you a handle to refer to that target in other steps,
so you don't have to use system-specific strings yourself.
&SCons; can also scan automatically for dependency information,
such as header files included by source code files
(for example, <literal>#include</literal>
preprocessor directives in C or C++ files),
so these <firstterm>implicit dependencies</firstterm> do not
have to be specified manually.
&SCons; supports the ability to define new scanners
to support additional input file types.
</para>

<para>Information about files involved in the build,
including a cryptographic hash of the contents of source files,
is cached for later reuse.
By default, this hash (the <firstterm>&contentsig;</firstterm>)
is used to decide if a file has changed since the last build,
although other algorithms can be used by selecting an appropriate
<firstterm>&f-link-Decider;</firstterm> function.
Implicit dependency files are also part of out-of-date computation.
The scanned implicit dependency information can optionally be
cached and used to speed up future builds.
A hash of each executed build action (the <firstterm>&buildsig;</firstterm>)
is also cached, so that changes to build instructions (changing flags, etc.)
or to the build tools themselves (e.g. a compiler upgrade)
can also trigger a rebuild.
</para>

<para>
&SCons; supports separated source and build
directories (also called "out-of-tree builds")
through the definition of
<firstterm>variant directories</firstterm>
Using a separated build directory helps keep
the source directory clean of artifacts when doing searches,
allows setting up differing builds ("variants") without conflicts,
and allows resetting the build by just removing the build directory
(note that SCons does have a "clean" mode as well).
See the &f-link-VariantDir; description for more details.
</para>

<para>
When invoked, &scons;
looks for a file describing the build configuration
in the current directory and reads that in.
The file is by default named &SConstruct;,
although some variants of that,
or a developer-chosen name, are also accepted
(see <xref linkend="sconscript_files"/>).
If found, the current directory
is set as the project top directory.
Certain command-line options specify alternate
places to look for &SConstruct;
(see
<link linkend="opt-directory"><option>-C</option></link>,
<link linkend="opt-D"><option>-D</option></link>,
<link linkend="opt-up"><option>-u</option></link> and
<link linkend="opt-U"><option>-U</option></link>),
which will set the project top directory to the path found.
A path to the build configuration can also be
specified with the
<link linkend="opt-f"><option>-f</option></link> option,
which leaves the current directory as the project top directory.
</para>

<para>
The build configuration may be split into multiple files:
the &SConstruct; file can specify additional
configuration files by calling the
&f-link-SConscript; function,
and any file thus invoked may
include further files in the same way.
By convention,
these subsidiary files are named
&SConscript;,
although any name may be used.
As a result of this naming convention,
the term <firstterm>&SConscript; files</firstterm>
is used to refer
generically to the complete set of
configuration files for a project
(including the &SConstruct; file),
regardless of the actual file names or number of such files.
A hierarchical build is not recursive - all of
the SConscript files are processed in a single pass
so that &scons; has a picture of the complete
dependency tree when it begins considering what needs building.
Each SConscript file is processed in a separate context
so settings made in one script do not leak into another;
information can however be shared explicitly between scripts.
</para>

<para>Before reading the SConscript files,
&scons;
looks for a <firstterm>site directory</firstterm> -
a directory named <filename>site_scons</filename>
is searched for in various system directories and in the
project top directory, or if the
<link linkend="opt-site-dir"><option>--site-dir</option></link>
option is given, checks only for that directory.
Found site directories are prepended
to the &Python; module search path (<varname>sys.path</varname>),
thus allowing modules in such directories to be imported in
the normal &Python; way in &SConscript; files.
For each found site directory,
(1) if it contains a file <filename>site_init.py</filename>
that file is evaluated,
and (2) if it contains a directory
<filename>site_tools</filename> the path to that directory
is prepended to the default toolpath.
See the
<link linkend="opt-site-dir"><option>--site-dir</option></link>
and
<link linkend="opt-no-site-dir"><option>--no-site-dir</option></link>
options for details on default paths and
controlling the site directories.
</para>

<para>
&SConscript; files are written in the
<firstterm>&Python;</firstterm> programming language.
For many tasks, the simple syntax can be understood from examples,
so it is normally not necessary to be a &Python;
programmer to use &SCons; effectively.
&SConscript; files are executed in a context that makes
the facilities described in this manual page directly
available (that is, no need to <literal>import</literal>).
Standard &Python; scripting capabilities
such as flow control, data manipulation, and imported &Python; modules
are available to use in more complicated build configurations.
Other &Python; files can be made a part of the build system,
but they do not automatically have the &SCons; context and
need to import it if they need access (described later).
</para>

<para>
&SCons; reads and executes all of the included &SConscript; files
<emphasis>before</emphasis>
it begins building any targets.
Progress messages show this behavior
(the state change lines - those
beginning with the <literal>scons:</literal> tag -
may be suppressed using the
<link linkend="opt-Q"><option>-Q</option></link> option):
</para>

<screen>
$ <userinput>scons foo.out</userinput>
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets  ...
cp foo.in foo.out
scons: done building targets.
$
</screen>

<para>
To assure reproducible builds,
&SCons;
uses a restricted <firstterm>execution environment</firstterm>
for running external commands used to build targets,
rather than propagating the full environment
in effect at the time &scons; was called.
This helps avoid problems like picking up accidental
or malicious settings,
temporary debug values that are no longer needed,
or a developer having different settings than another
(or than the CI pipeline).
Environment variables needed for the proper
operation of such commands must be set in the
execution environment explicitly,
either by assigning the desired values,
or by picking those values individually or collectively
out of environment variables exposed by the &Python;
<systemitem>os.environ</systemitem> dictionary
(as external program inputs they should be validated
before use).
The execution environment for a given &consenv;
is its &cv-link-ENV; value.
A small number of  environment variables are picked up automatically
by &scons; itself (see <xref linkend="environment"/>).
</para>

<para>
In particular, if a compiler or other external command
needed to build a target file
is not in &scons;' idea of a standard system location,
it will not be found at runtime unless
you explicitly add the location into the
execution environment's <varname>PATH</varname> element.
This is a particular consideration on Windows platforms,
where it is common for a command to install into an app-specific
location and depend on setting
<varname>PATH</varname> in order for them to be found,
which does not automatically work for &SCons;.
</para>

<para>
One example approach is to
extract the entire <envar>PATH</envar>
environment variable and set that into the
execution environment:
</para>

<programlisting language="python">
import os
env = Environment(ENV={'PATH': os.environ['PATH']})
</programlisting>

<para>Similarly, if the commands use specific
external environment variables that &scons;
does not recognize, they can be propagated into
the execution environment:</para>

<programlisting language="python">
import os

env = Environment(
    ENV={
        'PATH': os.environ['PATH'],
        'MODULEPATH': os.environ['MODULEPATH'],
        'PKG_CONFIG_PATH': os.environ['PKG_CONFIG_PATH'],
    }
)
</programlisting>

<para>Or you can explicitly propagate the invoking user's
complete external environment:</para>

<programlisting language="python">
import os
env = Environment(ENV=os.environ.copy())
</programlisting>

<para>This comes at the expense of making your build
dependent on the user's environment being set correctly,
but it may be more convenient for some configurations.
It should not cause problems if done in a build setup which tightly
controls how the environment is set up before invoking
&scons;, as in many continuous
integration setups.
</para>

<note><para>
The above fragments are intended to illustrate a concept.
It is normally not a good idea to wipe out the entire
default value of the execution environment
(<literal>env["ENV"]</literal>),
as it may carry important information for the
execution of build commands.
</para></note>

<para>&scons;
is normally executed in a top-level directory containing an
&SConstruct; file (the project top directory).
When &scons; is invoked,
the command line (including the contents of the
<link linkend="v-SCONSFLAGS">&SCONSFLAGS;</link>
environment variable, if set) is processed.
Command-line options (see <xref linkend="options"/>) are consumed.
Any variable argument assignments are collected, and
remaining arguments are taken as targets to build.</para>

<para>Values of variables to be passed to the &SConscript; files
may be specified on the command line:</para>

<screen>
<userinput>scons debug=1</userinput>
</screen>

<para>These variables are available through the
<link linkend="v-ARGUMENTS">&ARGUMENTS;</link> dictionary,
and can be used in the &SConscript; files to modify
the build in any way:</para>

<programlisting language="python">
if ARGUMENTS.get("debug", ""):
    env = Environment(CCFLAGS="-g")
else:
    env = Environment()
</programlisting>

<para>The command-line variable arguments are also available
in the <link linkend="v-ARGLIST">&ARGLIST;</link> list,
indexed by their order on the command line.
This allows you to process them in order rather than by name,
if necessary. Each &ARGLIST; entry is a tuple consisting
of the name and the value.
</para>

<para>
See <xref linkend="commandline_construction_variables"/>
for more information.
</para>

<para>&scons;
can maintain a cache of target (derived) files that can
be shared between multiple builds.  When derived-file caching is enabled in an
&SConscript; file, any target files built by
&scons;
will be copied
to the cache.  If an up-to-date target file is found in the cache, it
will be retrieved from the cache instead of being rebuilt locally.
Caching behavior may be disabled and controlled in other ways by the
<link linkend="opt-cache-force"><option>--cache-force</option></link>,
<link linkend="opt-cache-disable"><option>--cache-disable</option></link>,
<link linkend="opt-cache-readonly"><option>--cache-readonly</option></link>,
and
<link linkend="opt-cache-show"><option>--cache-show</option></link>
command-line options.  The
<link linkend="opt-random"><option>--random</option></link>
option is useful to prevent multiple builds
from trying to update the cache simultaneously.</para>

<!--  The following paragraph reflects the default tool search orders -->
<!--  currently in SCons/Tool/__init__.py.  If any of those search orders -->
<!--  change, this documentation should change, too. -->

<para>By default,
&scons;
searches for known programming tools
on various systems and initializes itself based on what is found.
On Windows systems which identify as <emphasis>win32</emphasis>,
&scons;
searches in order for the
&MSVC; tools,
the MinGW tool chain,
the Intel compiler tools,
the GCC tools,
the LLVM/clang tools,
and the PharLap ETS compiler.
On Windows system which identify as <emphasis>cygwin</emphasis>
(that is, if &scons; is invoked from a cygwin shell),
the order changes to prefer the GCC toolchain over the MSVC tools.
<!-- Seems odd to still list OS/2 (though it lives in some form as ArcaOS -->
On OS/2 systems,
&scons;
searches in order for the
OS/2 compiler,
the GCC tool chain,
and the &MSVC; tools,
On SGI IRIX, IBM AIX, Hewlett Packard HP-UX, and Oracle Solaris systems,
&scons;
searches for the native compiler tools
(MIPSpro, Visual Age, aCC, and Forte tools respectively)
and the GCC tool chain.
On all other platforms,
including POSIX (Linux and UNIX) and macOS platforms,
&scons;
searches in order
for the GCC tool chain,
the LLVM/clang tools,
and the Intel compiler tools.
The default tool selection can be pre-empted
through the use of the <parameter>tools</parameter>
argument to &consenv; creation methods,
explicitly calling the &f-link-Tool; loader,
the through the setting of various setting of &consvars;.
</para>

<refsect2 id='target_selection'>
<title>Target Selection</title>

<para>&SCons; acts on the <firstterm>selected targets</firstterm>,
whether the requested operation is build, no-exec or clean.
Targets are selected as follows:
</para>
<orderedlist>
<listitem>
<para>
Targets specified on the command line.
These may be files, directories,
or phony targets defined using the &f-link-Alias; function.
Directory targets are scanned by &scons; for any targets
that may be found with a destination in or under that directory.
The targets listed on the command line are made available in the
<link linkend="v-COMMAND_LINE_TARGETS">&COMMAND_LINE_TARGETS;</link> list.
</para>
</listitem>
<listitem>
<para>If no targets are specified on the command line,
&scons; will select those targets
specified in the &SConscript; files via calls
to the &f-link-Default; function. These are
known as the <firstterm>default targets</firstterm>,
and are made available in the
<link linkend="v-DEFAULT_TARGETS">&DEFAULT_TARGETS;</link> list.
</para>
</listitem>
<listitem>
<para>
If no targets are selected by the previous steps,
&scons; selects the current directory for scanning,
unless command-line options which affect the directory
for target scanning are present
(<link linkend="opt-directory"><option>-C</option></link>,
<link linkend="opt-D"><option>-D</option></link>,
<link linkend="opt-up"><option>-u</option></link>,
<link linkend="opt-U"><option>-U</option></link>).
Since targets thus selected were not the result of
user instructions, this target list is not made available
for direct inspection; use the
<link linkend="opt-debug"><option>--debug=explain</option></link>
option if they need to be examined.
</para>
</listitem>
<listitem>
<para>
&scons; always adds to the selected targets any intermediate
targets which are necessary to build the specified ones.
For example, if constructing a shared library or dll from C
source files, &scons; will also build the object files which
will make up the library.
</para>
</listitem>
</orderedlist>

<para>To ignore the default targets specified
through calls to &Default; and instead build all
target files in or below the current directory
specify the current directory (<literal>.</literal>)
as a command-line target:</para>

<screen>
<userinput>scons .</userinput>
</screen>

<para>To build all target files,
including any files outside of the current directory,
supply a command-line target
of the root directory (on POSIX systems):</para>

<screen>
<userinput>scons /</userinput>
</screen>

<para>or the path name(s) of the volume(s) in which all the targets
should be built (on Windows systems):</para>

<screen>
<userinput>scons C:\ D:\</userinput>
</screen>

<para>A subset of a hierarchical tree may be built by
remaining at the project top directory
and specifying the subdirectory as the target to
build:</para>

<screen>
<userinput>scons src/subdir</userinput>
</screen>

<para>or by changing directory and invoking scons with the
<link linkend="opt-up"><option>-u</option></link>
option, which traverses up the directory
hierarchy until it finds the
&SConstruct;
file, and then builds
targets relatively to the current subdirectory (see
also the related
<link linkend="opt-D"><option>-D</option></link>
and
<link linkend="opt-U"><option>-U</option></link>
options):</para>

<screen>
<userinput>cd src/subdir</userinput>
<userinput>scons -u .</userinput>
</screen>

<para>In all cases, more files may be built than are
requested, as &scons; needs to make
sure any dependent files are built.</para>

<para>Specifying "cleanup" targets in &SConscript; files is
usually not necessary.
The
<link linkend="opt-clean"><option>-c</option></link>
flag removes all selected targets:
</para>

<screen>
<userinput>scons -c .</userinput>
</screen>

<para>to remove all target files in or under the current directory, or:</para>

<screen>
<userinput>scons -c build export</userinput>
</screen>

<para>to remove target files under <filename>build</filename>
and <filename>export</filename>.</para>

<para>
Additional files or directories to remove can be specified using the
&f-link-Clean; function in the &SConscript; files.
Conversely, targets that would normally be removed by the
<option>-c</option>
invocation can be retained by calling the
&f-link-NoClean; function with those targets.</para>

<para>&scons;
supports building multiple targets in parallel via a
<link linkend="opt-jobs"><option>-j</option></link>
option that takes, as its argument, the number
of simultaneous tasks that may be spawned:</para>

<screen>
<userinput>scons -j 4</userinput>
</screen>

<para>builds four targets in parallel, for example.</para>

</refsect2>
</refsect1>

<refsect1 id='options'>
<title>OPTIONS</title>

<para>In general,
&scons;
supports the same command-line options as GNU &Make;
and many of those supported by <application>cons</application>.
</para>

<!-- The recommended approach of multiple <term> entries per <varlistentry> -->
<!-- (if needed) is not used for Options, because the default docbook -->
<!-- presentation format for a varlist has been changed in SCons from -->
<!-- csv to one-per-line to improve the display of Builders and -->
<!-- Functions/Methods in those sections. Do the csv manually. -->

<!-- Note: commented-out options are retained as they may be a model -->
<!-- for future development directions. Do not remove. -->

<variablelist>
  <varlistentry id="opt-b">
  <term><option>-b</option></term>
  <listitem>
<para>Ignored for compatibility with non-GNU versions of &Make;</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-clean">
  <term>
    <option>-c</option>,
    <option>--clean</option>,
    <option>--remove</option>
  </term>
  <listitem>
<para>Set <firstterm>clean</firstterm> mode.
Clean up by removing the selected targets,
well as any files or directories associated
with a selected target through calls to the &f-link-Clean; function.
Will not remove any targets which are marked for
preservation through calls to the &f-link-NoClean; function.
</para>
<para>
While clean mode removes targets rather than building them,
work which is done directly in &Python; code in &SConscript; files
will still be carried out.  If it is important to avoid some
such work from taking place in clean mode, it should be protected.
An &SConscript; file can determine which mode
is active by querying &f-link-GetOption;, as in the call
<code>if GetOption("clean"):</code>
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-cache-debug">
  <term><option>--cache-debug=<replaceable>file</replaceable></option></term>
  <listitem>
<para>Write debug information about
derived-file caching to the specified
<replaceable>file</replaceable>.
If
<replaceable>file</replaceable>
is a hyphen
(<literal>-</literal>),
the debug information is printed to the standard output.
The printed messages describe what signature-file names
are being looked for in, retrieved from, or written to the
derived-file cache specified by &f-link-CacheDir;.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-cache-disable">
  <term>
    <option>--cache-disable</option>,
    <option>--no-cache</option>
  </term>
  <listitem>
<para>Disable derived-file caching.
&scons;
will neither retrieve files from the cache
nor copy files to the cache.  This option can
be used to temporarily disable the cache without
modifying the build scripts.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-cache-force">
  <term>
    <option>--cache-force</option>,
    <option>--cache-populate</option>
  </term>
  <listitem>
<para>When using &f-link-CacheDir;,
populate a derived-file cache by copying any already-existing,
up-to-date derived files to the cache,
in addition to files built by this invocation.
This is useful to populate a new cache with
all the current derived files,
or to add to the cache any derived files
recently built with caching disabled via the
<option>--cache-disable</option>
option.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-cache-readonly">
  <term><option>--cache-readonly</option></term>
  <listitem>
<para>Use the derived-file cache, if enabled, to retrieve files,
but do not not update the cache with any files actually
built during this invocation.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-cache-show">
  <term><option>--cache-show</option></term>
  <listitem>
<para>When using a derived-file cache, show the command
that would have been executed to build the file
(or the corresponding <literal>*COMSTR</literal>
contents if set)
even if the file is retrieved from cache.
Without this option, &scons; shows a cache retrieval message
if the file is fetched from cache.
This allows producing consistent output for build logs,
regardless of whether a target
file was rebuilt or retrieved from the cache.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-config">
  <term><option>--config=<replaceable>mode</replaceable></option></term>
  <listitem>
<para>Control how the &f-link-Configure;
call should use or generate the
results of configuration tests.
<replaceable>mode</replaceable> should be one of
the following choices:</para>

  <variablelist> <!-- nested list -->
  <varlistentry>
  <term><emphasis role="bold">auto</emphasis></term>
  <listitem>
<para>&SCons; will use its normal dependency mechanisms
to decide if a test must be rebuilt or not.
This saves time by not running the same configuration tests
every time you invoke scons,
but will overlook changes in system header files
or external commands (such as compilers)
if you don't specify those dependencies explicitly.
This is the default behavior.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">force</emphasis></term>
  <listitem>
<para>If this mode is specified,
all configuration tests will be re-run
regardless of whether the
cached results are out-of-date.
This can be used to explicitly
force the configuration tests to be updated
in response to an otherwise unconfigured change
in a system header file or compiler.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">cache</emphasis></term>
  <listitem>
<para>If this mode is specified,
no configuration tests will be rerun
and all results will be taken from cache.
&scons; will report an error
if <option>--config=cache</option> is specified
and a necessary test does not
have any results in the cache.</para>
  </listitem>
  </varlistentry>
  </variablelist> <!-- end nested list -->

  </listitem>
  </varlistentry>

  <varlistentry id="opt-directory">
  <term>
    <option>-C <replaceable>directory</replaceable></option>,
    <option>--directory=<replaceable>directory</replaceable></option>
  </term>
  <listitem>
<para>Run as if &scons; was started in
<replaceable>directory</replaceable>
instead of the current working directory.
That is, change directory before searching for the
&SConstruct;,
&Sconstruct;,
&sconstruct;,
&SConstruct.py;,
&Sconstruct.py;
or
&sconstruct.py;
file or doing anything else.
When multiple
<option>-C</option>
options are given, each subsequent non-absolute
<option>-C</option> <replaceable>directory</replaceable>
is interpreted relative to the preceding one.
See also options
<link linkend="opt-up"><option>-u</option></link>,
<link linkend="opt-U"><option>-U</option></link>
and
<link linkend="opt-D"><option>-D</option></link>
to change the &SConstruct; search behavior when this option is used.
</para>
  </listitem>
  </varlistentry>

<!--  .TP -->
<!--  \-d -->
<!--  Display dependencies while building target files.  Useful for -->
<!--  figuring out why a specific file is being rebuilt, as well as -->
<!--  general debugging of the build process. -->

  <varlistentry id="opt-D">
  <term><option>-D</option></term>
  <listitem>
<para>Works exactly the same way as the
<link linkend="opt-up"><option>-u</option></link>
option except for the way default targets are handled.
When this option is used and no targets are specified on the command line,
all default targets are built, whether or not they are below the current
directory.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-debug">
  <term><option>--debug=<replaceable>type</replaceable>[<replaceable>,type</replaceable>...]</option></term>
  <listitem>
<para>Debug the build process.
<replaceable>type</replaceable>
specifies the kind of debugging info to emit.
Multiple types may be specified, separated by commas.
The following types are recognized:</para>

  <variablelist> <!-- nested list -->
  <varlistentry>
  <term><emphasis role="bold">action-timestamps</emphasis></term>
  <listitem>
<para>Prints additional time profiling information. For
each command, shows the absolute start and end times.
This may be useful in debugging parallel builds.
Implies the <option>--debug=time</option> option.
</para>
<para><emphasis>New in version 3.1.</emphasis></para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">count</emphasis></term>
  <listitem>
<para>Print how many objects are created
of the various classes used internally by SCons
before and after reading the &SConscript; files
and before and after building targets.
This is not supported when SCons is executed with the &Python;
<option>-O</option>
(optimized) option
or when the SCons modules
have been compiled with optimization
(that is, when executing from
<filename>*.pyo</filename>
files).</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">duplicate</emphasis></term>
  <listitem>
<para>Print a line for each unlink/relink (or copy) of a file in
a variant directory from its source file.
Includes debugging info for unlinking stale variant directory files,
as well as unlinking old targets before building them.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">explain</emphasis></term>
  <listitem>
<para>Print an explanation of why &scons;
is deciding to (re-)build the targets
it selects for building.
</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">findlibs</emphasis></term>
  <listitem>
<para>Instruct the scanner that searches for libraries
to print a message about each potential library
name it is searching for,
and about the actual libraries it finds.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">includes</emphasis></term>
  <listitem>
<para>Print the include tree after each top-level target is built.
This is generally used to find out what files are included by the sources
of a given derived file:</para>

<screen>
$ <userinput>scons --debug=includes foo.o</userinput>
</screen>

  </listitem>
  </varlistentry>

<varlistentry>
  <term><emphasis role="bold">json</emphasis></term>
  <listitem>
    <para>Write info to a JSON file for any of the following debug options if they are enabled: <emphasis>memory</emphasis>,
    <emphasis>count</emphasis>, <emphasis>time</emphasis>, <emphasis>action-timestamps</emphasis> </para>
    <para>The default output file is <literal>scons_stats.json</literal></para>
    <para>The file name/path can be modified by using &f-link-DebugOptions; for example <literal>DebugOptions(json='path/to/file.json')</literal></para>

<screen>
$ <userinput>scons --debug=memory,json foo.o</userinput>
</screen>

  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">memoizer</emphasis></term>
  <listitem>
<para>Prints a summary of hits and misses using the Memoizer,
an internal subsystem that counts
how often SCons uses cached values in memory
instead of recomputing them each time they're needed.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">memory</emphasis></term>
  <listitem>
<para>Prints how much memory SCons uses
before and after reading the &SConscript; files
and before and after building targets.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">objects</emphasis></term>
  <listitem>
<para>Prints a list of the various objects
of the various classes used internally by SCons.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">pdb</emphasis></term>
  <listitem>
<para>Run &scons; under control of the
<systemitem>pdb</systemitem>
&Python; debugger.</para>
<screen>
$ <userinput>scons --debug=pdb</userinput>
> /usr/lib/python3.11/site-packages/SCons/Script/Main.py(869)_main()
-> options = parser.values
(Pdb)
</screen>
<note>
<para><systemitem>pdb</systemitem> will stop at the
beginning of the &scons; main routine on startup.
The search path (<systemitem>sys.path</systemitem>)
at that point will include the location of the running &scons;,
but not of the project itself.
If you need to set breakpoints in your project files,
you will either need to add to the path,
or use absolute pathnames when referring to project files.
A <filename>.pdbrc</filename> file in the project root
can be used to add the current directory to the search path
to avoid having to enter it by hand,
along these lines:
</para>
<programlisting language="python">
sys.path.append('.')
</programlisting>
<para>
Due to the implementation of the
<systemitem>pdb</systemitem> module,
the <command>break</command>,
<command>tbreak</command>
and <command>clear</command>
commands only understand references to filenames
which have a <filename>.py</filename> extension.
(although the suffix itself can be omitted),
<emphasis>except</emphasis> if you use an absolute path.
As a special exception to that rule, the names
&SConstruct; and &SConscript; are recognized without
needing the <filename>.py</filename> extension.
</para>
<para>
<emphasis>Changed in version 4.6.0</emphasis>:
The names &SConstruct; and &SConscript; are now
recognized without requiring
<filename>.py</filename> suffix.
</para>
<para>
<emphasis>Changed in version 4.8.0</emphasis>:
The name <filename>SCsub</filename> is now recognized
without requiring <filename>.py</filename> suffix.
</para>
</note>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">prepare</emphasis></term>
  <listitem>
<para>Print a line each time any target (internal or external)
is prepared for building.
&scons;
prints this for each target it considers, even if that
target is up-to-date (see also <option>--debug=explain</option>).
This can help debug problems with targets that aren't being
built; it shows whether
&scons;
is at least considering them or not.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">presub</emphasis></term>
  <listitem>
<para>Print the raw command line used to build each target
before the &consenv; variables are substituted.
Also shows which targets are being built by this command.
Output looks something like this:</para>

<screen>
$ <userinput>scons --debug=presub</userinput>
Building myprog.o with action(s):
  $SHCC $SHCFLAGS $SHCCFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES
...
</screen>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">stacktrace</emphasis></term>
  <listitem>
<para>Prints an internal &Python; stack trace
when encountering an otherwise unexplained error.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">time</emphasis></term>
  <listitem>
<para>Prints various time profiling information:</para>
    <itemizedlist>
      <listitem>
<para>The time spent executing each individual build command</para>
      </listitem>
      <listitem>
<para>The total build time (time SCons ran from beginning to end)</para>
      </listitem>
      <listitem>
<para>The total time spent reading and executing &SConscript; files</para>
      </listitem>
      <listitem>
<para>The total time SCons itself spent running
(that is, not counting reading and executing &SConscript; files)</para>
      </listitem>
      <listitem>
<para>The total time spent executing all build commands</para></listitem>
      <listitem>
<para>The elapsed wall-clock time spent executing those build commands</para>
      </listitem>
      <listitem>
<para>The time spent processing each file passed to the &f-link-SConscript; function</para>
      </listitem>
    </itemizedlist>
<para>
(When
&scons;
is executed without the
<link linkend="opt-jobs"><option>-j</option></link>
option,
the elapsed wall-clock time will typically
be slightly longer than the total time spent
executing all the build commands,
due to the SCons processing that takes place
in between executing each command.
When
&scons;
is executed
<emphasis>with</emphasis>
the
<link linkend="opt-jobs"><option>-j</option></link>
option,
and your build configuration allows good parallelization,
the elapsed wall-clock time should
be significantly smaller than the
total time spent executing all the build commands,
since multiple build commands and
intervening SCons processing
should take place in parallel.)
</para>
  </listitem>
  </varlistentry>
  <varlistentry>
  <term><emphasis role="bold">sconscript</emphasis></term>
  <listitem>
<para>Enables output indicating entering and exiting each SConscript file.</para>
  </listitem>
  </varlistentry>
  </variablelist> <!-- end nested list -->
  </listitem>
  </varlistentry>

  <varlistentry id="opt-diskcheck">
  <term><option>--diskcheck=<replaceable>type</replaceable></option></term>
  <listitem>
<para>Enable specific checks for
whether or not there is a file on disk
where the SCons configuration expects a directory
(or vice versa)
when searching for source and include files.
<replaceable>type</replaceable>
can be an available diskcheck type or
the special tokens <literal>all</literal> or <literal>none</literal>.
A comma-separated string can be used to select multiple checks.
The default setting is <literal>all</literal>.
</para>

<para>Current available checks are:</para>
  <variablelist> <!-- nested list -->
  <varlistentry>
  <term><emphasis role="bold">match</emphasis></term>
  <listitem>
<para>to check that files and directories on disk
match SCons' expected configuration.</para>
  </listitem>
  </varlistentry>
  </variablelist> <!-- end nested list -->

<para>
Disabling some or all of these checks
can provide a performance boost for large configurations,
or when the configuration will check for files and/or directories
across networked or shared file systems,
at the slight increased risk of an incorrect build
or of not handling errors gracefully.
</para>

  </listitem>
  </varlistentry>

  <varlistentry id="opt-duplicate">
  <term><option>--duplicate=<replaceable>ORDER</replaceable></option></term>
  <listitem>
<para>There are three ways to duplicate files in a build tree: hard links,
soft (symbolic) links and copies. The default policy is to
prefer hard links to soft links to copies. You can specify a
different policy with this option.
<replaceable>ORDER</replaceable>
must be one of
<emphasis>hard-soft-copy</emphasis>
(the default),
<emphasis>soft-hard-copy</emphasis>,
<emphasis>hard-copy</emphasis>,
<emphasis>soft-copy</emphasis>
or
<emphasis>copy</emphasis>.
&SCons; will attempt to duplicate files using
the mechanisms in the specified order.</para>
  </listitem>
  </varlistentry>

<!--  .TP -->
<!--  \-e, \-\-environment\-overrides -->
<!--  Variables from the execution environment override construction -->
<!--  variables from the SConscript files. -->

  <varlistentry id="opt-enable-virtualenv">
  <term><option>--enable-virtualenv</option></term>
  <listitem>
<para>Import virtualenv-related variables to SCons.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-experimental">
    <term>
      <option>--experimental=<replaceable>feature</replaceable></option>
    </term>
    <listitem>
      <para>Enable experimental features and/or tools.
        <replaceable>feature</replaceable> can be an available feature name or
        the special tokens <literal>all</literal> or <literal>none</literal>.
        A comma-separated string can be used to select multiple features.
        The default setting is <literal>none</literal>.</para>
      <para>Current available features are:
        <literal>ninja</literal> (<emphasis>New in version 4.2</emphasis>),
        <literal>legacy_sched</literal> (<emphasis>New in version 4.6.0</emphasis>).
      </para>
      <caution><para>
        No Support offered for any features or tools enabled by this flag.
      </para></caution>
      <para><emphasis>New in version 4.2 (experimental).</emphasis></para>
    </listitem>
  </varlistentry>

  <varlistentry id="opt-sconstruct">
    <term>
      <option>-f <replaceable>file</replaceable></option>,
      <option>--file=<replaceable>file</replaceable></option>,
      <option>--makefile=<replaceable>file</replaceable></option>,
      <option>--sconstruct=<replaceable>file</replaceable></option>
    </term>
    <listitem>
      <para>Use
        <replaceable>file</replaceable>
        as the initial &SConscript; file.
        Multiple
        <option>-f</option>
        options may be specified,
        in which case
        &scons;
        will read all of the specified files.
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id="opt-help">
  <term>
    <option>-h</option>,
    <option>--help</option>
  </term>
  <listitem>
<para>Print a local help message for this project,
if one is defined in the &SConscript; files
(see the &f-link-Help; function),
plus a line that refers to the standard &SCons; help message.
If no local help message is defined,
prints the standard &SCons; help message
(as for the <option>-H</option> option)
plus help for any local options defined through &f-link-AddOption;.
Exits after displaying the appropriate message.</para>
<para>
Note that use of this option requires &SCons; to process
the &SConscript; files, so syntax errors may cause
the help message not to be displayed.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-hash-chunksize">
  <term>
    <option>--hash-chunksize=<replaceable>KILOBYTES</replaceable></option>
  </term>
  <listitem>
<para>Set the block size used when computing &contentsigs; to
<replaceable>KILOBYTES</replaceable>.
This value determines the size of the chunks which are read in at once when
computing signature hashes.  Files below that size are fully stored in memory
before performing the signature computation while bigger files are read in
block-by-block. A huge block-size leads to high memory consumption while a very
small block-size slows down the build considerably.</para>

<para>The default value is to use a chunk size of 64 kilobytes, which should
be appropriate for most uses.</para>

<para><emphasis>New in version 4.1.</emphasis></para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-hash-format">
  <term>
    <option>--hash-format=<replaceable>ALGORITHM</replaceable></option>
  </term>
  <listitem>
<para>Set the hashing algorithm used by SCons to
<replaceable>ALGORITHM</replaceable>.
This value determines the hashing algorithm used in generating
&contentsigs;, &buildsigs; and &CacheDir; keys.</para>

<para>The supported list of values are:
<parameter>md5</parameter>,
<parameter>sha1</parameter>
and <parameter>sha256</parameter>.
However, the &Python; interpreter used to run &scons; must have the corresponding
support available in the <systemitem>hashlib</systemitem> module
to use the specified algorithm.</para>

<para>If this option is omitted,
the first supported hash format found is selected.
Typically, this is MD5, however, on a FIPS-compliant system
using a version of &Python; older than 3.9,
SHA1 or SHA256 is chosen as the default.
&Python; 3.9 and onwards clients always default to MD5, even in FIPS mode.
</para>

<para>Specifying this option changes the name of the SConsign database.
The default database is <filename>.sconsign.dblite</filename>.
In the presence of this option,
<replaceable>ALGORITHM</replaceable> is
included in the name to indicate the difference,
even if the argument is <parameter>md5</parameter>.
For example, <option>--hash-format=sha256</option> uses a SConsign
database named <filename>.sconsign_sha256.dblite</filename>.
</para>

<para><emphasis>New in version 4.1.</emphasis></para>
  </listitem>
</varlistentry>

  <varlistentry id="opt-H">
  <term>
    <option>-H</option>,
    <option>--help-options</option>
  </term>
  <listitem>
<para>Print the standard help message about &SCons;
command-line options and exit.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-ignore-errors">
  <term>
    <option>-i</option>,
    <option>--ignore-errors</option>
  </term>
  <listitem>
<para>Ignore all errors from commands executed to rebuild files.</para>

  </listitem>
  </varlistentry>

  <varlistentry id="opt-include-dir">
  <term>
    <option>-I <replaceable>directory</replaceable></option>,
    <option>--include-dir=<replaceable>directory</replaceable></option>
  </term>
  <listitem>
<para>Specifies a
<replaceable>directory</replaceable>
to search for
imported &Python; modules.  If several
<option>-I</option>
options
are used, the directories are searched in the order specified.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-ignore-virtualenv">
  <term><option>--ignore-virtualenv</option></term>
  <listitem>
<para>Suppress importing virtualenv-related variables to SCons.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-implicit-cache">
  <term><option>--implicit-cache</option></term>
  <listitem>
<para>Cache implicit dependencies.
This causes
&scons;
to use the implicit (scanned) dependencies
from the last time it was run
instead of scanning the files for implicit dependencies.
This can significantly speed up SCons,
but with the following limitations:</para>

<para>&scons;
will not detect changes to implicit dependency search paths
(e.g.  &cv-link-CPPPATH;, &cv-link-LIBPATH;)
that would ordinarily
cause different versions of same-named files to be used.</para>

<para>&scons;
will miss changes in the implicit dependencies
in cases where a new implicit
dependency is added earlier in the implicit dependency search path
(e.g.  &cv-link-CPPPATH;, &cv-link-LIBPATH;)
than a current implicit dependency with the same name.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-implicit-deps-changed">
  <term><option>--implicit-deps-changed</option></term>
  <listitem>
<para>Forces SCons to ignore the cached implicit dependencies. This causes the
implicit dependencies to be rescanned and recached. This implies
<option>--implicit-cache</option>.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-implicit-deps-unchanged">
  <term><option>--implicit-deps-unchanged</option></term>
  <listitem>
<para>Force SCons to ignore changes in the implicit dependencies.
This causes cached implicit dependencies to always be used.
This implies
<option>--implicit-cache</option>.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-install-sandbox">
  <term><option>--install-sandbox=<replaceable>sandbox_path</replaceable></option></term>
  <listitem>
<para>
When using the &Install; builders, prepend
<replaceable>sandbox_path</replaceable>
to the installation paths such that all installed files will be placed
under that directory. This option is unavailable if
one of &b-link-Install;, &b-link-InstallAs; or
&b-link-InstallVersionedLib; is not used in the &SConscript; files.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-interactive">
  <term><option>--interactive</option></term>
  <listitem>
<para>Starts SCons in interactive mode.
The &SConscript; files are read once and a
<computeroutput>scons&gt;&gt;&gt;</computeroutput>
prompt is printed.
Targets may now be rebuilt by typing commands at interactive prompt
without having to re-read the &SConscript; files
and re-initialize the dependency graph from scratch.</para>

<para>SCons interactive mode supports the following commands:</para>

    <variablelist>
      <varlistentry>
      <term><userinput>build <parameter>[OPTIONS] [TARGETS] ...</parameter></userinput></term>
      <listitem>
<para>Builds the specified
<parameter>TARGETS</parameter>
(and their dependencies)
with the specified
SCons command-line
<parameter>OPTIONS</parameter>.
<emphasis role="bold">b</emphasis>
and
<emphasis role="bold">scons</emphasis>
are synonyms for
<emphasis role="bold">build</emphasis>.
</para>

<para>The following SCons command-line options affect the
<emphasis role="bold">build</emphasis>
command:</para>

<literallayout class="monospaced">
--cache-debug=FILE
--cache-disable, --no-cache
--cache-force, --cache-populate
--cache-readonly
--cache-show
--debug=TYPE
-i, --ignore-errors
-j N, --jobs=N
-k, --keep-going
-n, --no-exec, --just-print, --dry-run, --recon
-Q
-s, --silent, --quiet
--taskmastertrace=FILE
--tree=OPTIONS
</literallayout>

<para>Any other SCons command-line options that are specified
do not cause errors
but have no effect on the
<emphasis role="bold">build</emphasis>
command
(mainly because they affect how the &SConscript; files are read,
which only happens once at the beginning of interactive mode).</para>
      </listitem>
      </varlistentry>

      <varlistentry>
      <term><userinput>clean <parameter>[OPTIONS] [TARGETS] ...</parameter></userinput></term>
      <listitem>
<para>Cleans the specified
<parameter>TARGETS</parameter>
(and their dependencies)
with the specified
<parameter>OPTIONS</parameter>.
<emphasis role="bold">c</emphasis>
is a synonym.
This command is itself a synonym for
<userinput>build --clean</userinput></para>
      </listitem>
      </varlistentry>

      <varlistentry>
      <term><userinput>exit</userinput></term>
      <listitem>
<para>Exits SCons interactive mode.
You can also exit by terminating input
(<keycombo action="simul">
<keycap>Ctrl</keycap>
<keycap>D</keycap>
</keycombo>
UNIX or Linux systems,
(<keycombo action="simul">
<keycap>Ctrl</keycap>
<keycap>Z</keycap>
</keycombo>
on Windows systems).</para>
      </listitem>
      </varlistentry>

      <varlistentry>
      <term><userinput>help <parameter>[COMMAND]</parameter></userinput></term>
      <listitem>
<para>Provides a help message about
the commands available in SCons interactive mode.
If
<emphasis>COMMAND</emphasis>
is specified,
<emphasis role="bold">h</emphasis>
and
<emphasis role="bold">?</emphasis>
are synonyms.</para>
      </listitem>
      </varlistentry>

      <varlistentry>
      <term><userinput>shell <parameter>[COMMANDLINE]</parameter></userinput></term>
      <listitem>
<para>Executes the specified
<parameter>COMMANDLINE</parameter>
in a subshell.
If no
<parameter>COMMANDLINE</parameter>
is specified,
executes the interactive command interpreter
specified in the
<envar>SHELL</envar>
environment variable
(on UNIX and Linux systems)
or the
<envar>COMSPEC</envar>
environment variable
(on Windows systems).
<emphasis role="bold">sh</emphasis>
and
<emphasis role="bold">!</emphasis>
are synonyms.</para>
      </listitem>
      </varlistentry>

      <varlistentry>
      <term><userinput>version</userinput></term>
      <listitem>
<para>Prints SCons version information.</para>
      </listitem>
      </varlistentry>
    </variablelist>

<para>An empty line repeats the last typed command.
Command-line editing can be used if the
<emphasis role="bold">readline</emphasis>
module is available.</para>

<screen>
$ <userinput>scons --interactive</userinput>
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons&gt;&gt;&gt; build -n prog
scons&gt;&gt;&gt; exit
</screen>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-jobs">
  <term>
    <option>-j <replaceable>N</replaceable></option>,
    <option>--jobs=<replaceable>N</replaceable></option>
  </term>
  <listitem>
<para>Specifies the maximum number of concurrent jobs (commands) to run.
If there is more than one
<option>-j</option>
option, the last one is effective.</para>
<!--  ??? If the -->
<!--  .B \-j -->
<!--  option -->
<!--  is specified without an argument, -->
<!--  .B scons -->
<!--  will not limit the number of -->
<!--  simultaneous jobs. -->
  </listitem>
  </varlistentry>

  <varlistentry id="opt-keep-going">
  <term>
    <option>-k</option>,
    <option>--keep-going</option>
  </term>
  <listitem>
<para>Continue as much as possible after an error.  The target that
failed and those that depend on it will not be remade, but other
targets specified on the command line will still be processed.</para>
  </listitem>
  </varlistentry>

<!--  .TP -->
<!--  .RI  \-l " N" ", \-\-load\-average=" N ", \-\-max\-load=" N -->
<!--  No new jobs (commands) will be started if -->
<!--  there are other jobs running and the system load -->
<!--  average is at least -->
<!--  .I N -->
<!--  (a floating\-point number). -->

<!--  .TP -->
<!--  \-\-list\-derived -->
<!--  List derived files (targets, dependencies) that would be built, -->
<!--  but do not build them. -->
<!--  [XXX This can probably go away with the right -->
<!--  combination of other options.  Revisit this issue.] -->

<!--  .TP -->
<!--  \-\-list\-actions -->
<!--  List derived files that would be built, with the actions -->
<!--  (commands) that build them.  Does not build the files. -->
<!--  [XXX This can probably go away with the right -->
<!--  combination of other options.  Revisit this issue.] -->

<!--  .TP -->
<!--  \-\-list\-where -->
<!--  List derived files that would be built, plus where the file is -->
<!--  defined (file name and line number).  Does not build the files. -->
<!--  [XXX This can probably go away with the right -->
<!--  combination of other options.  Revisit this issue.] -->

  <varlistentry id="opt-m">
  <term><option>-m</option></term>
  <listitem>
<para>Ignored for compatibility with non-GNU versions of &Make;.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-max-drift">
  <term><option>--max-drift=<replaceable>SECONDS</replaceable></option></term>
  <listitem>
<para>Set the maximum expected drift in the modification time of files to
<replaceable>SECONDS</replaceable>.
This value determines how long a file must be unmodified
before its cached &contentsig;
will be used instead of
calculating a new &contentsig; (hash)
of the file's contents.
The default value is 2 days, which means a file must have a
modification time of at least two days ago in order to have its
cached &contentsig; used.
A negative value means to never cache the
&contentsig; and to ignore the cached value if there already is one.
A value of 0 means to always use the cached signature,
no matter how old the file is.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><option>--md5-chunksize=<replaceable>KILOBYTES</replaceable></option></term>
  <listitem>
<para>A deprecated synonym for
<link linkend="opt-hash-chunksize"><option>--hash-chunksize</option></link>.
</para>

<para><emphasis>Changed in version 4.2:</emphasis> deprecated.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-no-exec">
  <term>
    <option>-n</option>,
    <option>--no-exec</option>,
    <option>--just-print</option>,
    <option>--dry-run</option>,
    <option>--recon</option>
  </term>
  <listitem>
<para>Set <firstterm>no-exec</firstterm> mode.
Print the commands that would be executed to build
any out-of-date targets, but do not execute those commands.
</para>

<para>
Only target building is suppressed - any work in the build
system that is done directly (in regular &Python; code)
will still be carried out. You can add guards around
code which should not be executed in no-exec mode by
checking the value of the option at run time with &f-link-GetOption;:
</para>
<programlisting language="python">
if not GetOption("no_exec"):
    # run regular instructions
</programlisting>

<para>The output is a best effort, as &SCons; cannot always precisely
determine what would be built.  For example, if a file generated
by a builder action is also used as a source in the build,
that file is not available to scan for dependencies at all
in an unbuilt tree, and may contain out-of-date information in a
previously built tree.
</para>
<para>
&SCons; cannot perform &f-link-Configure; checks in no-exec mode,
as they would make changes to the filesystem
(see &cv-link-CONFIGUREDIR; and &cv-link-CONFIGURELOG;).
It can use stored information from a previous build,
if it is not out-of-date,
so a "priming" build may make subsequent no-exec runs
more useful.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-no-site-dir">
  <term><option>--no-site-dir</option></term>
  <listitem>
<para>Do not read site directories.
Neither the standard site directories
(<filename>site_scons</filename>)
nor the path specified via a previous
<option>--site-dir</option> option are
added to the module search path <varname>sys.path</varname>,
searched for a <filename>site_init.py</filename> file,
or have their <filename>site_tools</filename>
directory included in the tool search path.
Can be overridden by a subsequent
<option>--site-dir</option> option.
</para>
  </listitem>
  </varlistentry>

<!--  .TP -->
<!--  .RI \-o " file" ", \-\-old\-file=" file ", \-\-assume\-old=" file -->
<!--  Do not rebuild -->
<!--  .IR file , -->
<!--  and do -->
<!--  not rebuild anything due to changes in the contents of -->
<!--  .IR file . -->
<!--  .TP -->
<!--  .RI \-\-override " file" -->
<!--  Read values to override specific build environment variables -->
<!--  from the specified -->
<!--  .IR file . -->

<!--  .TP -->
<!--  \-p -->
<!--  Print the data base (construction environments, -->
<!--  Builder and Scanner objects) that are defined -->
<!--  after reading the SConscript files. -->
<!--  After printing, a normal build is performed -->
<!--  as usual, as specified by other command\-line options. -->
<!--  This also prints version information -->
<!--  printed by the -->
<!--  .B \-v -->
<!--  option. -->

<!--  To print the database without performing a build do: -->

<!--  .ES -->
<!--  scons \-p \-q -->
<!--  .EE -->

  <varlistentry id="opt-package-type">
  <term><option>--package-type=<replaceable>type</replaceable></option></term>
  <listitem>
<para>The type
of package to create when using the &b-link-Package; builder.
Multiple types can be specified by using a comma-separated string,
in which case &SCons; will try to build for all of those package types.
Note this option is only available if the &t-link-packaging; tool
has been enabled.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-profile">
  <term><option>--profile=<replaceable>file</replaceable></option></term>
  <listitem>
<para>Run &SCons; under the &Python; profiler
and save the results to <replaceable>file</replaceable>.
The results may be analyzed using the &Python;
<systemitem>pstats</systemitem> module.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-question">
  <term>
    <option>-q</option>,
    <option>--question</option></term>
  <listitem>
<para>Do not run any commands, or print anything.  Just return an exit
status that is zero if the specified targets are already up-to-date,
non-zero otherwise.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-Q">
  <term><option>-Q</option></term>
  <listitem>
<para>Suppress status messages about
reading &SConscript; files,
building targets
and entering directories.
Commands that are executed
to rebuild target files are still printed.</para>
  </listitem>
  </varlistentry>

<!--  .TP -->
<!--  \-r, \-R, \-\-no\-builtin\-rules, \-\-no\-builtin\-variables -->
<!--  Clear the default construction variables.  Construction -->
<!--  environments that are created will be completely empty. -->

  <varlistentry id="opt-random">
  <term><option>--random</option></term>
  <listitem>
<para>Build dependencies in a random order.  This is useful when
building multiple trees simultaneously with caching enabled,
to prevent multiple builds from simultaneously trying to build
or retrieve the same target files.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-silent">
  <term>
    <option>-s</option>,
    <option>--silent</option>,
    <option>--quiet</option>
  </term>
  <listitem>
<para>Silent.  Do not print commands that are executed to rebuild
target files.
Also suppresses SCons status messages.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-no-keep-going">
  <term>
    <option>-S</option>,
    <option>--no-keep-going</option>,
    <option>--stop</option>
  </term>
  <listitem>
<para>Ignored for compatibility with GNU &Make;</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-site-dir">
  <term><option>--site-dir=<replaceable>path</replaceable></option></term>
  <listitem>
<para>Use <replaceable>path</replaceable> as the site directory
rather than searching the list of default site directories.
This directory will be prepended to
<varname>sys.path</varname>,
the module
<filename><replaceable>path</replaceable>/site_init.py</filename>
will be loaded if it exists, and
<filename><replaceable>path</replaceable>/site_tools</filename>
will be included in the tool search path.
The option is not additive - if given more than once,
the last <replaceable>path</replaceable> wins.
</para>

<para>The default set of site directories searched when
<option>--site-dir</option>
is not specified depends on the system platform, as follows.
Users or system administrators can tune site-specific or
project-specific &SCons; behavior by setting up a
site directory in one or more of these locations.
Directories are examined in the order given, from most
generic ("system" directories) to most specific (in the current project),
so the last-executed <filename>site_init.py</filename> file is
the most specific one, giving it the chance to override
everything else), and the directories are prepended to the paths, again so
the last directory examined comes first in the resulting path.</para>

    <variablelist>
      <varlistentry>
      <term>Windows:</term>
      <listitem>
<literallayout class="monospaced">
%ALLUSERSPROFILE%/scons/site_scons
%LOCALAPPDATA%/scons/site_scons
%APPDATA%/scons/site_scons
%USERPROFILE%/.scons/site_scons
./site_scons
</literallayout>
<para>
Note earlier versions of the documentation listed a different
path for the "system" site directory, this path is still checked
but its use is discouraged:
</para>
<literallayout class="monospaced">
%ALLUSERSPROFILE%/Application Data/scons/site_scons
</literallayout>
      </listitem>
      </varlistentry>

      <varlistentry>
      <term>Mac OS X:</term>
      <listitem>
<literallayout class="monospaced">
/Library/Application Support/SCons/site_scons
/opt/local/share/scons/site_scons (for MacPorts)
/sw/share/scons/site_scons (for Fink)
$HOME/Library/Application Support/SCons/site_scons
$HOME/.scons/site_scons
./site_scons
</literallayout>
      </listitem>
      </varlistentry>

      <varlistentry>
      <term>Solaris:</term>
      <listitem>
<literallayout class="monospaced">
/opt/sfw/scons/site_scons
/usr/share/scons/site_scons
$HOME/.scons/site_scons
./site_scons
</literallayout>
      </listitem>
      </varlistentry>

      <varlistentry>
      <term>Linux, HPUX, and other Posix-like systems:</term>
      <listitem>
<literallayout class="monospaced">
/usr/share/scons/site_scons
$HOME/.scons/site_scons
./site_scons
</literallayout>
      </listitem>
      </varlistentry>
    </variablelist>

  </listitem>
  </varlistentry>

  <varlistentry id="opt-stack-size">
  <term><option>--stack-size=<replaceable>KILOBYTES</replaceable></option></term>
  <listitem>
<para>Set the size stack used to run threads to
<replaceable>KILOBYTES</replaceable>.
This value determines the stack size of the threads used to run jobs.
These threads execute the actions of the builders for the
nodes that are out-of-date.
This option has no effect unless the number of concurrent
build jobs is larger than one (as set by <option>-j N</option> or
<option>--jobs=N</option> on the command line or &SetOption; in a script).
</para>
<para>
Using a stack size that is too small may cause stack overflow errors.
This usually shows up as segmentation faults that cause scons to abort
before building anything.  Using a stack size that is too large will
cause scons to use more memory than required and may slow down the entire
build process.
The default value is to use a stack size of 256 kilobytes, which should
be appropriate for most uses.  You should not need to increase this value
unless you encounter stack overflow errors.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-touch">
  <term>
    <option>-t</option>,
    <option>--touch</option>
  </term>
  <listitem>
<para>Ignored for compatibility with GNU &Make;.
(Touching a file to make it
appear up-to-date is unnecessary when using &scons;.)</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-taskmastertrace">
  <term><option>--taskmastertrace=<replaceable>file</replaceable></option></term>
  <listitem>
<para>Prints trace information to the specified
<replaceable>file</replaceable>
about how the internal Taskmaster object
evaluates and controls the order in which Nodes are built.
A file name of
<emphasis role="bold">-</emphasis>
may be used to specify the standard output.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-tree">
  <term><option>--tree=<replaceable>type</replaceable>[<replaceable>,type</replaceable>...]</option></term>
  <listitem>
<para>Prints a tree of the dependencies
after each top-level target is built.
This prints out some or all of the tree,
in various formats,
depending on the
<replaceable>type</replaceable>
specified:</para>

  <variablelist> <!-- nested list -->
  <varlistentry>
  <term><emphasis role="bold">all</emphasis></term>
  <listitem>
<para>Print the entire dependency tree
after each top-level target is built.
This prints out the complete dependency tree,
including implicit dependencies and ignored dependencies.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">derived</emphasis></term>
  <listitem>
<para>Restricts the tree output to only derived (target) files,
not source files.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">linedraw</emphasis></term>
  <listitem>
<para>Draw the tree output using Unicode line-drawing characters
instead of plain ASCII text. This option acts as a modifier
to the selected <replaceable>type</replaceable>(s). If
specified alone, without any <replaceable>type</replaceable>,
it behaves as if <emphasis role="bold">all</emphasis>
had been specified.
</para>
<para><emphasis>New in version 4.0.</emphasis></para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">status</emphasis></term>
  <listitem>
<para>Prints status information for each displayed node.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">prune</emphasis></term>
  <listitem>
<para>Prunes the tree to avoid repeating dependency information
for nodes that have already been displayed.
Any node that has already been displayed
will have its name printed in
<emphasis role="bold">[square brackets]</emphasis>,
as an indication that the dependencies
for that node can be found by searching
for the relevant output higher up in the tree.</para>
  </listitem>
  </varlistentry>
  </variablelist> <!-- end nested list -->

<para>Multiple <replaceable>type</replaceable>
choices may be specified, separated by commas:</para>

<screen>
# Prints only derived files, with status information:
<userinput>scons --tree=derived,status</userinput>

# Prints all dependencies of target, with status information
# and pruning dependencies of already-visited Nodes:
<userinput>scons --tree=all,prune,status target</userinput>
</screen>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-up">
  <term>
    <option>-u</option>,
    <option>--up</option>,
    <option>--search-up</option>
  </term>
  <listitem>
<para>Walks up the directory structure until an
&SConstruct;, &Sconstruct;, &sconstruct;, &SConstruct.py;,
&Sconstruct.py; or &sconstruct.py;
file is found, and uses that
as the project top directory.
If no targets are specified on the command line,
only targets at or below the
current directory will be built.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-U">
  <term><option>-U</option></term>
  <listitem>
<para>Works exactly the same way as the
<option>-u</option>
option except for the way default targets are handled.
When this option is used and no targets are specified on the command line,
all default targets that are defined in the &SConscript; file(s) in the current
directory are built, regardless of what directory the resultant targets end
up in.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-version">
  <term>
    <option>-v</option>,
    <option>--version</option>
  </term>
  <listitem>
<para>Print the
&scons;
version, copyright information,
list of authors, and any other relevant information.
Then exit.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-print-directory">
  <term>
    <option>-w</option>,
    <option>--print-directory</option>
  </term>
  <listitem>
<para>Print a message containing the working directory before and
after other processing.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-no-print-directory">
  <term><option>--no-print-directory</option></term>
  <listitem>
<para>Turn off -w, even if it was turned on implicitly.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="opt-warn">
  <term>
    <option>--warn=<replaceable>type</replaceable></option>,
    <option>--warn=no-<replaceable>type</replaceable></option>
  </term>
  <listitem>
<para>Enable or disable (with the prefix "no-") warnings
(<option>--warning</option> is a synonym).
<replaceable>type</replaceable>
specifies the type of warnings to be enabled or disabled:</para>

  <variablelist> <!-- nested list -->
  <varlistentry>
  <term><emphasis role="bold">all</emphasis></term>
  <listitem>
<para>All warnings.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">cache-version</emphasis></term>
  <listitem>
<para>Warnings about the derived-file cache directory
specified by &f-link-CacheDir; not using
the latest configuration information.
These warnings are enabled by default.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">cache-write-error</emphasis></term>
  <listitem>
<para>Warnings about errors trying to
write a copy of a built file to a specified
derived-file cache specified by &f-link-CacheDir;.
These warnings are disabled by default.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">cache-cleanup-error</emphasis></term>
  <listitem>
<para>Warnings about errors when a file retrieved
from the derived-file cache could not be removed.
</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">corrupt-sconsign</emphasis></term>
  <listitem>
<para>Warnings about unfamiliar signature data in
<filename>.sconsign</filename>
files.
These warnings are enabled by default.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">dependency</emphasis></term>
  <listitem>
<para>Warnings about dependencies.
These warnings are disabled by default.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">deprecated</emphasis></term>
  <listitem>
<para>Warnings about use of
currently deprecated features.
These warnings are enabled by default.
Not all deprecation warnings can be disabled with the
<option>--warn=no-deprecated</option> option as some
deprecated features which are late in the deprecation
cycle may have been designated as mandatory warnings,
and these will still display.
Warnings for certain deprecated features
may also be enabled or disabled individually;
see below.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">duplicate-environment</emphasis></term>
  <listitem>
<para>Warnings about attempts to specify a build
of a target with two different &consenvs;
that use the same action.
These warnings are enabled by default.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">fortran-cxx-mix</emphasis></term>
  <listitem>
<para>Warnings about linking
Fortran and C++ object files in a single executable,
which can yield unpredictable behavior with some compilers.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">future-reserved-variable</emphasis></term>
  <listitem>
<para>Warnings about &consvars; which
are currently allowed,
but will become reserved variables in a future release.
</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">future-deprecated</emphasis></term>
  <listitem>
<para>Warnings about features
that will be deprecated in the future.
Such warnings are disabled by default.
Enabling future deprecation warnings is
recommended for projects that redistribute
SCons configurations for other users to build,
so that the project can be warned as soon as possible
about to-be-deprecated features
that may require changes to the configuration.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">link</emphasis></term>
  <listitem>
<para>Warnings about link steps.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">misleading-keywords</emphasis></term>
  <listitem>
<para>Warnings about the use of two commonly
misspelled keywords
<parameter>targets</parameter>
and
<parameter>sources</parameter>
to &f-link-Builder; calls. The correct spelling is the
singular form, even though
<parameter>target</parameter>
and
<parameter>source</parameter>
can themselves refer to lists of names or nodes.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">tool-qt-deprecated</emphasis></term>
  <listitem>
<para>Warnings about the &t-link-qt; tool being deprecated.
These warnings are disabled by default for the first
phase of deprecation. Enable to be reminded about use
of this tool module.
<emphasis>New in version 4.3.</emphasis>
</para>
  </listitem>
  </varlistentry>

  <!--varlistentry>   Removed in 4.6.0
  <term><emphasis role="bold">missing-sconscript</emphasis></term>
  <listitem>
<para>Warnings about missing &SConscript; files.
These warnings are enabled by default.</para>
  </listitem>
  </varlistentry-->

  <varlistentry>
  <term><emphasis role="bold">no-object-count</emphasis></term>
  <listitem>
<para>Warnings about the
<option>--debug=object</option>
feature not working when
&scons;
is run with the &Python;
<option>-O</option>
option or from optimized &Python; (<filename>.pyo</filename>) modules.</para>
<para>
Note the "no-" prefix is part of the name of this warning.
Add another "-no" to disable.
</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">no-parallel-support</emphasis></term>
  <listitem>
<para>Warnings about the version of &Python;
not being able to support parallel builds when the
<link linkend="opt-jobs"><option>-j</option></link>
option is used.
These warnings are enabled by default.</para>
<para>
Note the "no-" prefix is part of the name of this warning.
Add another "-no" to disable.
</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">python-version</emphasis></term>
  <listitem>
<para>Warnings about running
&SCons; using a version of &Python; that has been deprecated.
These warnings are enabled by default.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">reserved-variable</emphasis></term>
  <listitem>
<para>Warnings about attempts to set the
reserved &consvar; names
&cv-CHANGED_SOURCES;,
&cv-CHANGED_TARGETS;,
&cv-TARGET;,
&cv-TARGETS;,
&cv-SOURCE;,
&cv-SOURCES;,
&cv-UNCHANGED_SOURCES;
or
&cv-UNCHANGED_TARGETS;.
These warnings are disabled by default.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">stack-size</emphasis></term>
  <listitem>
<para>Warnings about requests to set the stack size
that could not be honored.
These warnings are enabled by default.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><emphasis role="bold">target-not-built</emphasis></term>
  <listitem>
<para>Warnings about a build rule not building the
 expected targets. These warnings are disabled by default.</para>
  </listitem>
  </varlistentry>
  </variablelist> <!-- end nested list -->
  </listitem>
  </varlistentry>

<!--  .TP -->
<!--  \-\-warn\-undefined\-variables -->
<!--  Warn when an undefined variable is referenced. -->

<!--  .TP -->
<!--  .RI \-\-write\-filenames= file -->
<!--  Write all filenames considered into -->
<!--  .IR file . -->

<!--  .TP -->
<!--  .RI \-W " file" ", \-\-what\-if=" file ", \-\-new\-file=" file ", \-\-assume\-new=" file -->
<!--  Pretend that the target -->
<!--  .I file -->
<!--  has been -->
<!--  modified.  When used with the -->
<!--  .B \-n -->
<!--  option, this -->
<!--  show you what would be rebuilt if you were to modify that file. -->
<!--  Without -->
<!--  .B \-n -->
<!--  ... what? XXX -->

  <varlistentry id="opt-repository">
  <term>
    <option>-Y <replaceable>repository</replaceable></option>,
    <option>--repository=<replaceable>repository</replaceable></option>,
    <option>--srcdir=<replaceable>repository</replaceable></option>
  </term>
  <listitem>
<para>
Search <replaceable>repository</replaceable>
for any input and target
files not found in the local directory hierarchy.
Multiple <option>-Y</option>
options may be specified,
with repositories searched in the given order.
See &f-link-Repository; for more information.
</para>
  </listitem>
  </varlistentry>
</variablelist>
</refsect1>

<refsect1 id='sconscript_file_reference'>
<title>SCONSCRIPT FILE REFERENCE</title>

<refsect2 id='sconscript_files'>
<title>SConscript Files</title>
<para>
The build configuration is described by one or more files,
known as &SConscript; files.
There must be at least one file for a valid build
(&scons; will quit if it does not find one).
&scons; by default looks for this file by the name
<filename>SConstruct</filename>
in the directory from which you run &scons;,
though if necessary, also looks for alternative file names
&Sconstruct;, &sconstruct;, &SConstruct.py;, &Sconstruct.py;
and &sconstruct.py; in that order.
A different file name (which can include a pathname part)
may be specified via the <option>-f</option> option.
Except for the &SConstruct; file,
these files are not searched for automatically;
you add additional configuration files to the build
by calling the &f-link-SConscript; function.
This allows parts of the build to be conditionally
included or excluded at run-time depending on how &scons; is invoked.
</para>

<para>
Each &SConscript; file in a build configuration is invoked
independently in a separate context.
This provides necessary isolation so that different parts of
the build don't accidentally step on each other.
You have to be explicit about sharing information,
by using the &f-link-Export; function or the &exports; argument
to the &f-link-SConscript; function, as well as the &f-link-Return; function
in a called &SConscript; file, and consume shared information by using the
&f-link-Import; function.
</para>

<para>
The following sections describe the various &SCons; facilities
that can be used in &SConscript; files.  Quick links:
</para>

<simplelist type="vert">
  <member><link linkend='construction_environments'>Construction Environments</link></member>
  <member><link linkend='tools'>Tools</link></member>
  <member><link linkend='builder_methods'>Builder Methods</link></member>
  <member><link linkend='env_methods'>Functions and Environment Methods</link></member>
  <member><link linkend='sconscript_variables'>SConscript Variables</link></member>
  <member><link linkend='construction_variables'>Construction Variables</link></member>
  <member><link linkend='configure_contexts'>Configure Contexts</link></member>
  <member><link linkend='commandline_construction_variables'>Command-Line Construction Variables</link></member>
  <member><link linkend='node_objects'>Node Objects</link></member>
</simplelist>

</refsect2>

<refsect2 id='construction_environments'>
<title>Construction Environments</title>

<para>A <firstterm>&ConsEnv;</firstterm> is the basic means by which
you communicate build information to
&SCons;.
A new &consenv; is created using the
&f-link-Environment;
function:</para>

<programlisting language="python">
env = Environment()
</programlisting>

<para>&Consenv; attributes called
<firstterm>&ConsVars;</firstterm> may be set
either by specifying them as keyword arguments when the object is created
or by assigning them a value after the object is created.
These two are nominally equivalent:</para>

<programlisting language="python">
env = Environment(FOO='foo')
env['FOO'] = 'foo'
</programlisting>

<!--TODO: how can the user tell which settings are init-only? -->
<para>Note that certain settings which affect tool detection are
referenced only when the tools are initialized,
so you need either to supply them as part of the call to
&f-link-Environment;, or defer tool initialization.
For example, initializing the &MSVC; version you wish to use:
</para>

<programlisting language="python">
# initializes msvc to v14.1
env = Environment(MSVC_VERSION="14.1")

env = Environment()
# msvc tool was initialized to default, does not reinitialize
env['MSVC_VERSION'] = "14.1"

env = Environment(tools=[])
env['MSVC_VERSION'] = "14.1"
# msvc tool initialization was deferred, so will pick up new value
env.Tool('default')
</programlisting>

<para>As a convenience,
&consvars; may also be set or modified by the
<parameter>parse_flags</parameter>
keyword argument during object creation,
which has the effect of the
&f-link-env-MergeFlags;
method being applied to the argument value
after all other processing is completed.
This is useful either if the exact content of the flags is unknown
(for example, read from a control file)
or if the flags need to be distributed to a number of &consvars;.
&f-link-env-ParseFlags; describes how these arguments
are distributed to &consvars;.
</para>

<programlisting language="python">
env = Environment(parse_flags='-Iinclude -DEBUG -lm')
</programlisting>

<para>This example adds 'include' to
the &cv-link-CPPPATH; &consvar;,
'EBUG' to
&cv-link-CPPDEFINES;,
and 'm' to
&cv-link-LIBS;.
</para>

<para>
An existing &consenv; can be duplicated by calling the &f-link-env-Clone;
method. Without arguments, it will be a copy with the same
settings. Otherwise, &f-env-Clone; takes the same arguments as
&f-link-Environment;, and uses the arguments to create a modified copy.
</para>

<para>
&SCons; provides a special &consenv; called the
<firstterm>&DefEnv;</firstterm>.
The &defenv; is used only for global functions, that is,
build requests called without the context of a regular &consenv;.
See &f-link-DefaultEnvironment; for more information.
</para>

<para>By default, a new &consenv; is
initialized with a set of builder methods
and &consvars; that are appropriate
for the current platform.
The optional <parameter>platform</parameter> keyword argument may be
used to specify that the &consenv; should
be initialized for a different platform:</para>

<programlisting language="python">
env = Environment(platform='cygwin')
</programlisting>

<para>Specifying a platform initializes the appropriate
&consvars; in the environment
to use and generate file names with prefixes
and suffixes appropriate for that platform.</para>

<para>Note that the
<literal>win32</literal>
platform adds the
<varname>SystemDrive</varname>
and
<varname>SystemRoot</varname>
variables from the user's external environment
to the &consenv;'s
<varname>ENV</varname>
dictionary.
This is so that any executed commands
that use sockets to connect with other systems
will work on Windows systems.</para>

<para>The <parameter>platform</parameter> argument may be
a string value representing
one of the pre-defined platforms
(<literal>aix</literal>,
<literal>cygwin</literal>,
<literal>darwin</literal>,
<literal>hpux</literal>,
<literal>irix</literal>,
<literal>os2</literal>,
<literal>posix</literal>,
<literal>sunos</literal> or
<literal>win32</literal>),
or a callable platform object
returned by a call to &f-link-Platform;
selecting a pre-defined platform,
or it may be a user-supplied callable,
in which case the &Environment; method
will call it to update
the new &consenv;:</para>

<programlisting language="python">
def my_platform(env):
    env['VAR'] = 'xyzzy'

env = Environment(platform=my_platform)
</programlisting>

<para>
Note that supplying a non-default platform or custom
function for initialization
may bypass settings that should happen for the host system
and should be used with care.
It is most useful in the case where the platform is an alternative for
the one that would be auto-detected,
such as <literal>platform="cygwin"</literal>
on a system which would otherwise
identify as <literal>win32</literal>.
</para>

<para>
The optional <parameter>tools</parameter> and <parameter>toolpath</parameter>
keyword arguments affect the way tools available to the environment are initialized.
See <xref linkend="tools"/> for details.
</para>

<para>
The optional <parameter>variables</parameter> keyword argument
allows passing a <classname>Variables</classname> object which will be used in the
initialization of the &consenv;
See <xref linkend="commandline_construction_variables"/> for details.
</para>

</refsect2>

<refsect2 id='tools'>
<title>Tools</title>

<para>
&SCons; has many included tool modules
(more properly, <firstterm>tool specification modules</firstterm>)
which are used to help initialize the &consenv; prior to building,
and more can be written to suit a particular purpose,
or added from external sources (a repository of
contributed tools is available).
More information on writing custom tools can be found in the
<link linkend='extending_scons'>Extending SCons</link> section
and specifically <link linkend='tool_modules'>Tool Modules</link>.
</para>

<para>
An &SCons; tool is only responsible for setup.
For example, if an &SConscript; file declares
the need to construct an object file from
a C-language source file by calling the
&b-link-Object; builder, then a tool module representing
an available C compiler needs to have run first,
to set up that builder and all the &consvars;
it needs in the associated &consenv;.
The tool itself is not called in the process of the build.
Tool setup happens when a &consenv; is constructed,
and in the basic case needs no intervention -
platform-specific lists of default tools are used
to examine the specific capabilities of that platform and
configure the environment,
skipping those tools which are not applicable.
</para>

<para>
If necessary, a specific set of tools to
initialize in an environment during creation
may be specified using the optional keyword argument
<parameter>tools</parameter>.
<parameter>tools</parameter> must be a list,
even if there are one (or zero) tools.
This is useful to override the defaults,
to specify non-default built-in tools,
and to cause added tools to be called:
</para>

<programlisting language="python">
env = Environment(tools=['msvc', 'lex'])
</programlisting>

<para>
The <parameter>tools</parameter> argument overrides
the default tool list, it does not add to it, so be
sure to include all the tools you need.
For example, if you are  building a c/c++ program,
you must specify a tool for at least a compiler and a linker,
as in <literal>tools=['clang', 'link']</literal>.
</para>

<para>
If the <parameter>tools</parameter> argument is omitted,
or if <parameter>tools</parameter> includes
the reserved name <literal>'default'</literal>,
then &SCons; will auto-detect usable tools,
using the search path from the execution environment
(that is, <varname><replaceable>env</replaceable>['ENV']['PATH']</varname>)
for looking up any external programs,
and the platform name in effect
to determine the default tools for that platform.
Note the contents of &PATH; from the external environment
<varname>os.environ</varname> is <emphasis>not</emphasis> used.
Changing the <varname>PATH</varname> in the execution environment
after the &consenv; is constructed will not cause the tools to
be re-detected.
</para>

<para>
Tools can also be directly called by using the &f-link-Tool;
method (see below).
</para>

<para>&SCons; supports the following tool specifications out of the box:</para>

<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->
<!-- '\" BEGIN GENERATED TOOL DESCRIPTIONS -->

<!-- '\" The descriptions below of the various SCons Tools are generated -->
<!-- '\" from the .xml files located together with the various Python -->
<!-- '\" tool modules in the build engine directory -->

<!-- '\" BEGIN GENERATED TOOL DESCRIPTIONS -->
<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->
<xsi:include xmlns:xsi="http://www.w3.org/2001/XInclude" href="../generated/tools.gen"/>
<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->
<!-- '\" END GENERATED TOOL DESCRIPTIONS -->

<!-- '\" The descriptions above of the various SCons Tools are generated -->
<!-- '\" from the .xml files located together with the various Python -->
<!-- '\" tool modules in the build engine directory -->

<!-- '\" END GENERATED TOOL DESCRIPTIONS -->
<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->

</refsect2>

<refsect2 id='builder_methods'>
<title>Builder Methods</title>

<para>
Builder methods are special functions
used to declare relationships in the build dependency graph.
Calling a Builder does not build anything directly,
but records the target or targets (what you want built),
sources (what it’s built from),
and the &consenv; to use for build settings.
The builder itself will typically have information
about producing targets which is also used,
except &b-link-Command;, where the caller is
responsible for specifying the action.
The &SCons; job runner later decides if and when
to initiate a build using this information.
</para>

<para>
All true Builder methods share the same function calling syntax.
For the sake of brevity, this common signature is not included in
the listing of Builders.
Pseudo-Builders have more flexibility in how they are called,
and do not necessarily follow this convention,
as described in the text of the respective entries.
</para>

<programlisting language="python">
<function>Buildername</function>(<parameter>target, source, [key=val, ...]</parameter>)
</programlisting>

<para>
The <parameter>target</parameter> and
<parameter>source</parameter> arguments
can be specified either as positional or keyword arguments.
Some additional keyword arguments are recognized for all builders,
and any unknown keyword arguments are treated as temporary
&consvar; assignments.
You can specify sources and targets as a scalar or a list,
composed of either strings or nodes.
For convenience, the &f-link-Split; method
can be used to split a single whitespace-separated string into a list.
</para>

<para>
&SCons; can resolve paths to sources and targets
specified in several different forms.
The <parameter>target</parameter> and
<parameter>source</parameter> arguments
can be scalar (string or Node) or a collection (of strings or Nodes).
</para>
<itemizedlist>
<listitem>
<para>
Nodes always work,
as they are the result of a previous successful path resolution;
if a path string is resolved correctly it is stored
internally as a Node in the dependency graph.
</para>
</listitem>
<listitem>
<para>
Plain file names (no pathname separators)
are searched for in the current directory.
</para>
</listitem>
<listitem>
<para>
Absolute paths (begin with a pathname separator)
are resolved by walking the path components
starting from root of the filesystem or current volume.
</para>
</listitem>
<listitem>
<para>
Relative paths (no leading pathname separator)
are resolved by walking the path components
starting from the current directory.
</para>
</listitem>
<listitem>
<para>
Top-relative paths are relative paths whose first character
is <emphasis role="bold">#</emphasis>.
They are walked starting from the project top-level directory
(usually, the directory where the &SConstruct; file is found).
Top-relative paths are always relative paths,
so the initial character can be followed by a pathname separator,
which is ignored and does not affect resolution.
</para>
</listitem>
<listitem>
<para>
UNC paths (Windows) start with exactly two pathname separators.
They take the form <literal>\\server_name\share_name\file_path</literal>.
The <varname>file_path</varname> portion is looked up as an
absolute path starting from the root of the
resource described by <literal>\\server_name\share_name</literal>.
Since UNC paths are never relative,
the top-relative path form does not apply.
</para>
</listitem>
<listitem>
<para>
URL-style strings and &Python; <systemitem>pathlib</systemitem>
objects are not recognized.
</para>
</listitem>
</itemizedlist>

<para>
The "current directory" for relative path resolution has options.
&SCons; by default changes to the directory containing the
&SConscript; file (including &SConstruct;) it is currently processing.
Use of the &f-link-SConscriptChdir; function toggles the
default behavior off/on.
The <parameter>srcdir</parameter> builder argument
affects where source file paths are looked for
(see details below).
Specifying one or more source code repositories via
the &f-link-Repository; function or the
<link linkend="opt-repository"><option>-Y/--repository</option></link>
option tells &SCons; to look additional places
after the actual current directory.
The concept of current directory changes for targets
(and in some cases sources) if a variant directory is set up using
the &f-link-VariantDir; function or the <parameter>variant_dir=</parameter>
parameter to the &f-link-SConscript; function.
These options do not affect top-relative paths.
</para>

<note>
<para>
On Windows, DOS paths may begin with a volume or drive letter
followed by the volume separator (<literal>:</literal>).
The remainder of the path is absolute or relative;
if the volume specifier is present,
resolution starts at the root of the specified drive for absolute paths
and the current directory on the specified drive for relative paths.
If the specified drive letter is different than the
current drive, a relative path is missing context:
since &SCons; is a console (command-line) application,
it may inherit state from the terminal it was started in,
including saved current directories for other drives;
&SCons; has no way of knowing what those would be.
Use of a drive letter in the path also precludes
the use of the top-relative form.
</para>
</note>

<para>
The following are equivalent examples of calling the
&Program; builder method:
</para>

<programlisting language="python">
env.Program('bar', ['bar.c', 'foo.c'])
env.Program('bar', Split('bar.c foo.c'))
env.Program('bar', env.Split('bar.c foo.c'))
env.Program(source=['bar.c', 'foo.c'], target='bar')
env.Program(target='bar', source=Split('bar.c foo.c'))
env.Program(target='bar', source=env.Split('bar.c foo.c'))
env.Program('bar', source='bar.c foo.c'.split())
</programlisting>

<para>Additional examples of source and target paths:</para>

<note>
<para>
Top-relative paths only work
where &SCons; will interpret the path (see examples).
The string must first be converted
to a relative or absolute path
to be used in other contexts
(such as pure &Python; code that does not
involve an &SCons; API call),
A suitable string can be extracted from the Node
created from a top-relative path.
Additionally, some paths are handled by &SCons; but
are not directly build participants,
so are not evaluated for the <literal>#</literal>
since no Nodes are created.
You can explcitly create a &f-link-File; or &f-link-Dir;
node to force evaluation,
such as when specifying a path to the derived-file cache:
<literal>CacheDir(Dir('#cache'))</literal>.
</para>
</note>

<programlisting language="python">
# The comments describing the targets that will be built
# assume these calls are in a SConscript file in the
# a subdirectory named "subdir".

# Builds the program "subdir/foo" from "subdir/foo.c":
env.Program('foo', 'foo.c')

# Builds the program "/tmp/bar" from "subdir/bar.c":
env.Program('/tmp/bar', 'bar.c')

# An initial '#' or '#/' are equivalent; the following
# calls build the programs "foo" and "bar" (in the
# top-level SConstruct directory) from "subdir/foo.c" and
# "subdir/bar.c", respectively:
env.Program('#foo', 'foo.c')
env.Program('#/bar', 'bar.c')

# Builds the program "other/foo" (relative to the top-level
# SConstruct directory) from "subdir/foo.c":
env.Program('#other/foo', 'foo.c')

# os.path.exists() is pure Python, so this fails:
if os.path.exists('#inc/foo.h'):
    env.Append(CPPPATH='#inc')

# create a Node to make it work:
if os.path.exists(File('#inc/foo.h')):
    env.Append(CPPPATH='#inc')
</programlisting>

<para>
If &SCons; can deduce the target name from the source(s),
the <parameter>target</parameter> argument may be omitted.
If the Builder supports it,
&SCons; will take the base name of the first source file
and use it as the base name of the target,
adding the appropriate prefix/suffix.
For Builders designated as single-source,
a separate target is built for each source file.
If multiple sources are passed to a single-source builder,
the target argument <emphasis>must</emphasis> be omitted,
and each target will be given a name deduced from
the corresponding source file.
</para>

<para>
The optional
<parameter>srcdir</parameter>
keyword argument specifies that
source file strings that are not absolute
or top-relative paths
are to be interpreted relative to the value of
<parameter>srcdir</parameter>.
The following example will build the
<filename>build/prog</filename>
(or
<filename>build/prog.exe</filename>
on Windows)
program from the files
<filename>src/f1.c</filename>
and
<filename>src/f2.c</filename>,
rather than looking for them in the directory of
of the &SConscript; file being evaluated.
</para>

<programlisting language="python">
env.Program('build/prog', ['f1.c', 'f2.c'], srcdir='src')
</programlisting>

<para>
The optional
<parameter>parse_flags</parameter>
keyword argument causes behavior similar to the
&f-link-env-MergeFlags; method, where the argument value is
broken into individual settings and merged into the appropriate &consvars;.
The following example adds <literal>'include'</literal> to
the &cv-link-CPPPATH; &consvar;,
<literal>'EBUG'</literal> to
&cv-link-CPPDEFINES;,
and <literal>'m'</literal> to
&cv-link-LIBS;:
</para>

<programlisting language="python">
env.Program('hello', 'hello.c', parse_flags='-Iinclude -DEBUG -lm')
</programlisting>

<para>
The optional
<parameter>chdir</parameter>
keyword argument
specifies that the Builder's action(s)
should be executed
after changing directory.
If the
<parameter>chdir</parameter>
argument is
a path string or a directory Node,
scons will change to the specified directory.
If the
<parameter>chdir</parameter>
is not a string or Node
and evaluates true,
then &scons; will change to the
target file's directory.
The original directory is restored
after the action is complete.
</para>

<programlisting language="python">
# scons will change to the "sub/dir" subdirectory
# before executing the Copy action function
env.Command(
    target='sub/dir/foo.out',
    source='sub/dir/foo.in',
    action=Copy('${TARGET.file}', '${SOURCE.file}'),
    chdir='sub/dir',
)

# Here, chdir is not a string, so scons will change to the
# target's directory ("sub/dir") to execute the action.
env.Command('
    target='sub/dir/foo.out',
    source='sub/dir/foo.in',
    action=Copy('${TARGET.file}', '${SOURCE.file}'),
    chdir=True
)
</programlisting>

<warning>
<para>
&Python; only tracks one current directory location,
even if there are multiple executing threads.
This means that use of the
<parameter>chdir</parameter>
argument will
<emphasis>not</emphasis>
work with &SCons; in multi-threaded mode
(the <link linkend="opt-jobs"><option>-j</option></link> option),
because individual worker threads spawned
by &SCons; interfere with each other
when they start changing directory.</para>
</warning>

<note>
<para>
&SCons; does not account for
<parameter>chdir</parameter>
when it expands &consvars;
like &cv-link-TARGET; and &cv-link-SOURCE;,
so they will be incorrect
relative to the chdir directory.
If you use the <parameter>chdir</parameter> keyword argument,
you will typically need to supply a different
command line using
expansions like
<literal>${TARGET.file}</literal>
and
<literal>${SOURCE.file}</literal>,
which expand to the filename portion of the
target and source.
</para>
</note>

<para>Keyword arguments that are not specifically
recognized are treated as &consvar;
<firstterm>overrides</firstterm>,
which replace or add those variables on a limited basis.
These overrides
will only be in effect when building the target of the builder call,
and will not affect other parts of the build.
For example, if you want to specify
some libraries needed by just one program:</para>

<programlisting language="python">
env.Program('hello', 'hello.c', LIBS=['gl', 'glut'])
</programlisting>

<para>or generate a shared library with a non-standard suffix:</para>

<programlisting language="python">
env.SharedLibrary(
    target='word',
    source='word.cpp',
    SHLIBSUFFIX='.ocx',
    LIBSUFFIXES=['.ocx'],
)
</programlisting>

<para>Note that both the &cv-link-SHLIBSUFFIX;
and &cv-link-LIBSUFFIXES;
&consvars; must be set if you want &scons; to search automatically
for dependencies on the non-standard library names;
see the descriptions of these variables for more information.</para>

<para>Although the builder methods defined by
&scons;
are, in fact,
methods of a &consenv; object,
many may also be called without an explicit environment:</para>

<programlisting language="python">
Program('hello', 'hello.c')
SharedLibrary('word', 'word.cpp')
</programlisting>

<para>If called this way, the builder will internally use the
&DefEnv; that consists of the tools and values that
&scons;
has determined are appropriate for the local system.</para>

<para>Builder methods that can be called without an explicit
environment (indicated in the listing of builders below
without a leading <varname>env.</varname>)
may be called from custom &Python; modules that you
import into an &SConscript; file by adding the following
to the &Python; module:</para>

<programlisting language="python">
from SCons.Script import *
</programlisting>

<para>
A builder <emphasis>may</emphasis> add additional targets
beyond those requested
if an attached <firstterm>Emitter</firstterm> chooses to do so
(see <xref linkend="builder_objects"/> for more information.
&cv-link-PROGEMITTER; is an example).
For example, the GNU linker takes a command-line argument
<option>-Map=<replaceable>mapfile</replaceable></option>,
which causes it to produce a linker map file in addition
to the executable file actually being linked.
If the &b-link-Program; builder's emitter is configured
to add this mapfile if the option is set,
then two targets will be returned when you only provided for one.
</para>

<para>
For this reason,
builder methods always return a <classname>NodeList</classname>,
a list-like object whose elements are Nodes.
Nodes are the internal representation of build targets or sources
(see <xref linkend="node_objects"/> for more information).
The returned <classname>NodeList</classname> object
can be passed to other builder methods as source(s)
or to other &SCons; functions or methods
where a path string would normally be accepted.
</para>

<para> For example,
to add a specific preprocessor define
when compiling one specific object file
but not the others:</para>

<programlisting language="python">
bar_obj_list = env.StaticObject('bar.c', CPPDEFINES='-DBAR')
env.Program("prog", ['foo.c', bar_obj_list, 'main.c'])
</programlisting>

<para>Using a Node as in this example
makes for a more portable build
by avoiding having to specify
a platform-specific object suffix
when calling the &b-link-Program; builder method.
</para>

<para>The <classname>NodeList</classname> object
is also convenient to pass to the &f-link-Default; function,
for the same reason of avoiding a platform-specific name:
</para>

<programlisting language="python">
tgt = env.Program("prog", ["foo.c", "bar.c", "main.c"])
Default(tgt)
</programlisting>

<para>
The Node representing the explicitly-requested target
is always the first element of the returned
<classname>NodeList</classname>,
and can be retrieved via list indexing
(e.g. <literal>bar_obj_list[0]</literal>).
The path name for a Node's file can be obtained
by using &Python;'s string constructor <function>str</function>
(e.g. <literal>str(bar_obj_list[0])</literal>).
</para>

<para>Builder calls will automatically "flatten"
lists passed as source and target, so they are free to
contain elements which are themselves lists, such as
<varname>bar_obj_list</varname>
returned by the &b-link-StaticObject; call.
If you need to manipulate a list of lists returned by builders
directly in &Python; code,
you can either build a new list by hand:</para>

<programlisting language="python">
foo = Object('foo.c')
bar = Object('bar.c')
objects = ['begin.o'] + foo + ['middle.o'] + bar + ['end.o']
for obj in objects:
    print(str(obj))
</programlisting>

<para>Or you can use the &f-link-Flatten;
function supplied by &SCons;
to create a list containing just the Nodes,
which may be more convenient:</para>

<programlisting language="python">
foo = Object('foo.c')
bar = Object('bar.c')
objects = Flatten(['begin.o', foo, 'middle.o', bar, 'end.o'])
for obj in objects:
    print(str(obj))
</programlisting>

<note>
<para>Since builder calls return
a list-like object, not an actual &Python; list,
it is not appropriate to use the &Python; add
operator (<literal>+</literal> or <literal>+=</literal>)
to append builder results to a &Python; list.
Because the list and the object are different types,
&Python; will not update the original list in place,
but will instead create a new <classname>NodeList</classname> object
containing the concatenation of the list
elements and the builder results.
This will cause problems for any other &Python; variables
in your SCons configuration
that still hold on to a reference to the original list.
Instead, use the &Python; list
<function>extend</function>
method to make sure the list is updated in-place.
Example:</para>

<programlisting language="python">
object_files = []

# Do NOT use += here:
#    object_files += Object('bar.c')
#
# It will not update the object_files list in place.
#
# Instead, use the list extend method:
object_files.extend(Object('bar.c'))
</programlisting>
</note>

<programlisting language="python">
bar_obj_list = env.StaticObject('bar.c', CPPDEFINES='-DBAR')
print("The path to bar_obj is:", str(bar_obj_list[0]))
</programlisting>

<para>
All targets of builder methods automatically depend on their sources.
&SCons; scans source files in various programming languages
for known dependency indications (e.g. <literal>#include</literal>
directives for sources that will be fed to the C preprocessor),
largely eliminating the need for explicit dependency specification.
You can also specify an explicit dependency
using the &f-link-env-Depends; method
of a &consenv;, although this is discouraged
unless the dependency cannot reliably be detected by an
existing scanner.
</para>

<para>
By default, &SCons; can scan
C source files, C++ source files,
Fortran source files with specific file extensions
(<filename>.F</filename>
(POSIX systems only),
<filename>.fpp</filename>,
or
<filename>.FPP</filename>)
and assembly language files with speicific file extensions
(<filename>.S</filename>
(POSIX systems only),
<filename>.spp</filename>,
or
<filename>.SPP</filename>)
for C preprocessor dependencies.
SCons also has default support
for scanning D, Java, SWIG and LaTeX source files.
</para>

<para>
Builders are created at runtime for efficiency
and added to the &consenv; as methods.
&SCons; provides templates for many
Builders for known build types,
and additional Builders can be written to add to a project.
The templates usually exist in
<link linkend='tools'>Tool specification modules</link>,
which, when run, can probe for the presence of required external tools,
such as a compiler binary,
and for other necessary conditions,
before instantiating the Builder.
The Builders available in a given &consenv; thus vary
with the type of platform, how the platform is provisioned,
and the tools selected for loading.
The available builder methods are registered as
key-value pairs in the &cv-link-BUILDERS; attribute of the &consenv;.
Although a Builder is created as a method of a &consenv;,
they may also be called as a global function.
A Builder called this way will internally use the
&DefEnv; to look up &consvars;:
</para>

<programlisting language="python">
Program('hello', 'hello.c')
SharedLibrary('word', 'word.cpp')
</programlisting>

<para>
Builders called in the global function style
are automatically in scope inside &SConscript; files.
They are not in scope
in project-specific &Python; modules that you include
via the &Python; <literal>import</literal> statement
from an &SConscript; file,
and you will need to add them to that module’s global scope explicitly.
You can do that by adding the following import to the &Python; module:
<userinput>from SCons.Script import *</userinput>.
</para>

<para>
The following builder methods have templates in the
&SCons; core software distribution.
</para>

<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->
<!-- '\" BEGIN GENERATED BUILDER DESCRIPTIONS -->

<!-- '\" The descriptions below of the various SCons Builders are generated -->
<!-- '\" from the .xml files located together with the various Python -->
<!-- '\" builder modules in the build engine directory -->

<!-- '\" BEGIN GENERATED BUILDER DESCRIPTIONS -->
<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->
<xsi:include xmlns:xsi="http://www.w3.org/2001/XInclude" href="../generated/builders.gen"/>
<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->
<!-- '\" END GENERATED BUILDER DESCRIPTIONS -->

<!-- '\" The descriptions abocve of the various SCons Builders are generated -->
<!-- '\" from the .xml files located together with the various Python -->
<!-- '\" builder modules in the build engine directory -->

<!-- '\" END GENERATED BUILDER DESCRIPTIONS -->
<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->

</refsect2>

<refsect2 id='env_methods'>
<title>&SCons; Functions and Environment Methods</title>

<para>
&SCons; provides a variety of &consenv; methods
and global functions to manipulate the build configuration.
Often, a &consenv; method and a global function with
the same name exist for convenience.
In this section, both forms are shown if the function can be called
in either way.
The documentation style for these is as follows:
</para>

<programlisting language="python">
<function>Function</function>(<parameter>arguments, [optional arguments, ...]</parameter>)  # Global function
<replaceable>env</replaceable>.<methodname>Function</methodname>(<parameter>arguments, [optional arguments, ...]</parameter>)  # Environment method
</programlisting>

<para>
In these function signatures,
arguments in brackets (<literal>[]</literal>) are optional,
and ellipses (<literal>...</literal>) indicate possible repetition.
Positional vs. keyword arguments are usually detailed
in the following text, not in the signature itself.
The &Python; positional-only (<literal>/</literal>)
and keyword-only (<literal>*</literal>) markers are not used.
</para>

<para>
When the &Python; <literal>keyword=value</literal> style is shown,
it can have two meanings.
If the keyword argument is known to the function,
the value is the default for that argument if it is omitted.
If the keyword is unknown to the function,
some methods treat it as a &consvar; assignment;
otherwise an exception is raised for an unknown argument.
</para>

<para>
A global function and a same-named &consenv; method
have the same base functionality,
with two key differences:
</para>

<orderedlist>
<listitem>
<para>
&Consenv; methods that read from or change the environment
act on the environment instance from which they are called,
while the corresponding global functions read from
a special “hidden” &consenv; called the &DefEnv;.
In some cases, a global function may take an extra
initial argument giving the object to operate on.
</para>
</listitem>
<listitem>
<para>
String-valued arguments
(including strings in list-valued arguments)
are subject to &consvar; expansion
by the environment method form;
variable expansion is not immediately performed in the global function.
For example, <userinput>Default('$MYTARGET')</userinput>
adds <computeroutput>'$MYTARGET'</computeroutput> to the
list of default targets,
while if the value in <parameter>env</parameter> of
<literal>MYTARGET</literal> is <literal>'mine'</literal>,
<userinput>env.Default('$MYTARGET'</userinput> adds
<computeroutput>'mine'</computeroutput>
to the default targets.
For more details on &consvar; expansion, see the
<link linkend="construction_variables">&Consvars;</link> section.
</para>
</listitem>
</orderedlist>

<para>
Global functions are automatically in scope inside &SConscript; files.
If your project adds &Python; modules that you include
via the &Python; <literal>import</literal> statement
from an &SConscript; file,
such code will need to add the functions
to that module’s global scope explicitly.
You can do that by adding the following import to the &Python; module:
<userinput>from SCons.Script import *</userinput>.
</para>

<para>
&SCons; provides the following &consenv; methods and global functions.
The list can be augmented on a project basis using &f-link-AddMethod;
</para>


<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->
<!-- '\" BEGIN GENERATED FUNCTION DESCRIPTIONS -->

<!-- '\" The descriptions below of the various SCons Tools are generated -->
<!-- '\" from the .xml files located together with the various Python -->
<!-- '\" modules in the build engine directory -->

<!-- '\" BEGIN GENERATED FUNCTION DESCRIPTIONS -->
<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->
<xsi:include xmlns:xsi="http://www.w3.org/2001/XInclude" href="../generated/functions.gen"/>
<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->
<!-- '\" END GENERATED FUNCTION DESCRIPTIONS -->

<!-- '\" The descriptions above of the various SCons Tools are generated -->
<!-- '\" from the .xml files located together with the various Python -->
<!-- '\" modules in the build engine directory -->

<!-- '\" END GENERATED FUNCTION DESCRIPTIONS -->
<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->

</refsect2>

<refsect2 id='sconscript_variables'>
<title>SConscript Variables</title>

<para>In addition to the global functions and methods,
&scons;
supports a number of variables
that can be used for run-time queries in &SConscript; files
to affect how you want the build to be performed.</para>

<variablelist>
  <varlistentry id="v-ARGLIST">
  <term>&ARGLIST;</term>
  <listitem>
<para>A list of the
<emphasis>variable</emphasis>=<emphasis>value</emphasis>
build variable arguments specified on the command line.
Each element in the list is a tuple
consisting of the variable and its value.
The separate
<emphasis>variable</emphasis>
and
<emphasis>value</emphasis>
elements of the tuple
can be accessed by
subscripting for elements
<emphasis role="bold">[0]</emphasis>
and
<emphasis role="bold">[1]</emphasis>
of the tuple, or, more readably, by using tuple unpacking.
Examples:</para>

<programlisting language="python">
print("first variable, value =", ARGLIST[0][0], ARGLIST[0][1])
print("second variable, value =", ARGLIST[1][0], ARGLIST[1][1])
var, value = ARGLIST[2]
print("third variable, value =", var, value)
for var, value in ARGLIST:
    # process variable and value
</programlisting>

<para>
The values obtained from &ARGLIST;
(or from <link linkend="v-ARGUMENTS">&ARGUMENTS;</link>)
are always strings since they originate from outside the &SCons; process.
As "untrusted data",
they should be validated before usage,
and may need conversion to an appropriate type.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="v-ARGUMENTS">
  <term>&ARGUMENTS;</term>
  <listitem>
<para>A dictionary of all the
<emphasis>variable</emphasis>=<emphasis>value</emphasis>
build variable arguments specified on the command line.
The dictionary is in command-line order,
so if a given variable has
more than one value assigned to it
on the command line,
the last (right-most) value is
the one saved in the &ARGUMENTS;
dictionary.</para>

<para>Example:</para>

<programlisting language="python">
if ARGUMENTS.get("debug", ""):
    env = Environment(CCFLAGS="-g")
else:
    env = Environment()
</programlisting>

<para>
See also <link linkend="v-ARGLIST">&ARGLIST;</link>.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="v-BUILD_TARGETS">
  <term>&BUILD_TARGETS;</term>
  <listitem>
<para>A list of the targets which
&scons;
has been asked to build.
The contents will be either those targets listed
on the command line, or, if none, those targets set
via calls to the &f-link-Default; function.
It does
<emphasis>not</emphasis>
contain any dependent targets that &scons;
selects for building as a result of making the sure the
specified targets are up to date, if those targets
did not appear on the command line.
The list is empty if neither
command line targets nor &Default; calls are present.
</para>
<para>
The elements of this list may be strings
<emphasis>or</emphasis>
nodes, so you should run the list through the &Python;
<function>str</function>
function to make sure any Node path names
are converted to strings.</para>

<para>Because this list may be taken from the
list of targets specified using the
&Default; function,
the contents of the list may change
on each successive call to &Default;.
See <link linkend="v-DEFAULT_TARGETS">&DEFAULT_TARGETS;</link>
for additional information.</para>

<para>Example:</para>

<programlisting language="python">
if 'foo' in BUILD_TARGETS:
    print("Don't forget to test the `foo' program!")
if 'special/program' in BUILD_TARGETS:
    SConscript('special')
</programlisting>
  </listitem>
  </varlistentry>

  <varlistentry id="v-COMMAND_LINE_TARGETS">
  <term>&COMMAND_LINE_TARGETS;</term>
  <listitem>
<para>A list of the targets explicitly specified on
the command line. If there are command line targets,
this list has the same contents as
<link linkend="v-BUILD_TARGETS">&BUILD_TARGETS;</link>.
If there are no targets specified on the command line,
this list is empty. The elements of this list are strings.
This can be used, for example,
to take specific actions only
when a certain target(s) are explicitly requested for building.</para>

<para>Example:</para>

<programlisting language="python">
if 'foo' in COMMAND_LINE_TARGETS:
    print("Don't forget to test the `foo' program!")
if 'special/program' in COMMAND_LINE_TARGETS:
    SConscript('special')
</programlisting>
  </listitem>
  </varlistentry>

  <varlistentry id="v-DEFAULT_TARGETS">
  <term>&DEFAULT_TARGETS;</term>
  <listitem>
<para>A list of the target
<emphasis>nodes</emphasis>
that have been specified using the
&f-link-Default;
function. If there are no command line
targets, this list will have the same contents as
<link linkend="v-BUILD_TARGETS">&BUILD_TARGETS;</link>.
Since the elements of the list are nodes,
you need to call the &Python;
<function>str</function>
function on them to get the path name for each Node.</para>

<para>Example:</para>

<programlisting language="python">
print(str(DEFAULT_TARGETS[0]))
if 'foo' in [str(t) for t in DEFAULT_TARGETS]:
    print("Don't forget to test the `foo' program!")
</programlisting>

<para>The contents of the
&DEFAULT_TARGETS;
list changes on each successive call to the
&Default; function:</para>

<programlisting language="python">
print([str(t) for t in DEFAULT_TARGETS])   # originally []
Default('foo')
print([str(t) for t in DEFAULT_TARGETS])   # now a node ['foo']
Default('bar')
print([str(t) for t in DEFAULT_TARGETS])   # now a node ['foo', 'bar']
Default(None)
print([str(t) for t in DEFAULT_TARGETS])   # back to []
</programlisting>

<para>Consequently, be sure to use
&DEFAULT_TARGETS;
only after you've made all of your
&Default;() calls,
or else simply be careful of the order
of these statements in your &SConscript; files
so that you don't look for a specific
default target before it's actually been added to the list.</para>
  </listitem>
  </varlistentry>
</variablelist>

<para>
These variables may be accessed from custom &Python; modules that you
import into an &SConscript; file by adding the following
to the &Python; module:</para>

<programlisting language="python">
from SCons.Script import *
</programlisting>

</refsect2>

<refsect2 id='construction_variables'>
<title>Construction Variables</title>
<!--  XXX From Gary Ruben, 23 April 2002: -->
<!--  I think it would be good to have an example with each construction -->
<!--  variable description in the documentation. -->
<!--  eg. -->
<!--  CC     The C compiler -->
<!--     Example: env["CC"] = "c68x" -->
<!--     Default: env["CC"] = "cc" -->

<!--  CCCOM  The command line ... -->
<!--     Example: -->
<!--         To generate the compiler line c68x \-ps \-qq \-mr \-o $TARGET $SOURCES -->
<!--         env["CC"] = "c68x" -->
<!--         env["CFLAGS"] = "\-ps \-qq \-mr" -->
<!--         env["CCCOM"] = "$CC $CFLAGS \-o $TARGET $SOURCES -->
<!--     Default: -->
<!--         (I dunno what this is ;\-) -->

<para>
<firstterm>&ConsVars;</firstterm> are key-value pairs
used to store information in a &consenv; that
is needed needed for builds using that environment.
&Consvar; naming must follow the same rules as
&Python; identifier naming:
the initial character must be an underscore or letter,
followed by any number of underscores, letters, or digits.
The convention is to use uppercase for all letters
for easier visual identification.
</para>

<para>
&Consvars; are used to hold many different types of information.
For example, the &cv-link-CPPDEFINES; variable is how to tell a C/C++
compiler about preprocessor macros you need for your build.
The tool discovery that &SCons; performs will cause the
&cv-link-CXX; variable to hold the name of the C++ compiler,
if one was detected on the system, but you can give it a different
value to force a compiler command of a different name to be used.
Some variables contain lists of filename suffixes that are recognized
by a particular compiler chain.
&cv-link-BUILDERS; contains a mapping of configured
Builder names (e.g. &b-link-Textfile;) to the actual Builder instance
to call when that Builder is used.
&Consvars; may include references to other &consvars;:
the same tool which set up the C/C++ compiler will also set
up an "action string", describing how to invoke that compiler,
in &cv-link-CXXCOM;, which contains other &consvars;
using <literal>$VARIABLE</literal> syntax.
These references will be expanded and replaced on use
(see <link linkend="variable_substitution">Variable Substitution</link>).
</para>

<para>
&Consvars; are referenced as if they were keys and values
in a &Python; dictionary:
</para>

<programlisting language="python">
env["CC"] = "cc"
flags = env.get("CPPDEFINES", [])
</programlisting>

<para>&Consvars; can also be retrieved and set
by using the &f-link-Dictionary;
method of the &consenv; to create an actual
dictionary:</para>

<programlisting language="python">
cvars = env.Dictionary()
cvars["CC"] = "cc"
</programlisting>

<para>
in the previous example, since <varname>cvars</varname>
is an external copy, the value of &cv-CC; in the
&consenv; itself is not changed by the assignment.
</para>

<para>&Consvars; can set by passing them as keyword arguments
when creating a new &consenv;:
</para>

<programlisting language="python">
env = Environment(CC="cc")
</programlisting>

<para>or when copying a &consenv; using the
&f-link-Clone; method:</para>

<programlisting language="python">
env2 = env.Clone(CC="cl.exe")
</programlisting>

<para>
&Consvars; can also be supplied as keyword
arguments to a builder, in which case those settings
affect only the work done by that builder call,
and not the &consenv; as a whole.
This concept is called an <firstterm>override</firstterm>:
</para>

<programlisting language="python">
env.Program('hello', 'hello.c', LIBS=['gl', 'glut'])
</programlisting>

<para>Many useful &consvars; are automatically defined by
&SCons;, tuned to the specific platform in use,
and you can modify these or define any additional &consvars;
for use in your own Builders, Scanners and other tools.
Take care not to overwrite ones which &SCons; is using.
The following is a list of predefined &consvars;.
Pay attention to whether the values are ones
you may be expected to set vs.
ones that are set to expected values by
internal tools and other initializations
and probably should not be modified.
</para>

<para>Note the actual list available
at execution time will never include all of these, as the ones
detected as not being applicable (wrong platform, necessary
external command or files not installed, etc.) will not be set up.
Correct build setups should be resilient to the possible
absence of certain &consvars; before using them,
for example by using a &Python; dictionary
<function>get</function> method to retrieve the value and
taking alternative action if the return indicates the variable is unset.
The &f-link-env-Dump; method can be called to examine the
&consvars; set in a particular environment.
</para>

<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->
<!-- '\" BEGIN GENERATED CONSTRUCTION VARIABLE DESCRIPTIONS -->

<!-- '\" The descriptions below of the various SCons construction variables -->
<!-- '\" are generated from the .xml files located together with the various -->
<!-- '\" Python modules in the build engine directory -->

<!-- '\" BEGIN GENERATED CONSTRUCTION VARIABLE DESCRIPTIONS -->
<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->
<xsi:include xmlns:xsi="http://www.w3.org/2001/XInclude" href="../generated/variables.gen"/>
<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->
<!-- '\" END GENERATED CONSTRUCTION VARIABLE DESCRIPTIONS -->

<!-- '\" The descriptions above of the various SCons construction variables -->
<!-- '\" are generated from the .xml files located together with the various -->
<!-- '\" Python modules in the build engine directory -->

<!-- '\" END GENERATED CONSTRUCTION VARIABLE DESCRIPTIONS -->
<!-- '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -->

</refsect2>

<refsect2 id='configure_contexts'>
<title>Configure Contexts</title>

<para>&SCons;
provides an integrated autoconfiguration mechanism
(inspired by GNU &Autoconf; but intrinsic to &SCons;),
for checking the existence of external items needed
for the build, such as C header files, libraries, etc.
This can be used to build optional features only
if support for them is available,
abort the build quickly if required elements are missing,
or just tune the build to the specific build platform.
The mechanism is portable across platforms.
</para>

<para>
You activate the configuration sysem by creating a
<firstterm>&configure_context;</firstterm>,
which holds accumulated information while the
checks are being performed,
request the desired checks,
and then transfer the information to the regular build environment.
Optionally, a configure header that C or C++
code can include can also be generated.
&SCons;
does not maintain an explicit cache of the tested values
(unlike &Autoconf;),
but uses its normal dependency tracking to keep the checked values
up to date. You may override this behavior with the
<link linkend="opt-config"><option>--config</option></link>
command line option.
</para>

<variablelist>
  <varlistentry>
  <term><function>Configure</function>(<parameter>env, [custom_tests, conf_dir, log_file, config_h, clean, help]</parameter>)</term>
  <term><replaceable>env</replaceable>.<methodname>Configure</methodname>(<parameter>[custom_tests, conf_dir, log_file, config_h, clean, help]</parameter>)</term>
  <listitem>
<para>Create a &configure_context;, which tracks information
discovered while running checks. The context includes a local &consenv;
(available as <replaceable>context</replaceable>.<varname>env</varname>)
which is used when running the checks and
which can be updated with the check results.
Only one context may be active
at a time, but a new context can be created
after the active one is completed.
For the global function form, the required <parameter>env</parameter>
describes the initial values for the context's local &consenv;;
for the &consenv; method form the instance provides the values.
</para>
<para><parameter>custom_tests</parameter>
specifies a dictionary containing custom checks
(see  <link linkend="custom_checks">details below</link>).
The default value is <constant>None</constant>,
to indicate there are no custom checks in the &configure_context;.</para>
<para>
<parameter>conf_dir</parameter>
specifies a directory where the test cases are built.
This directory is not used for building normal targets.
The default value is
<quote><filename>#/.sconf_temp</filename></quote>.</para>
<para>
<parameter>log_file</parameter>
specifies a file which collects the output from commands
that are executed to check for the existence of header files, libraries, etc.
The default is <quote><filename>#/config.log</filename></quote>.
If you are using variant directories,
you may want to place the log file for a given build
under that build's variant directory.</para>
<para>
<parameter>config_h</parameter>
specifies a C header file where the results of tests
will be written,
so the build can have access to this information by including it.
The results will consist of lines like
<literal>#define HAVE_GETADDRINFO 1</literal>,
<literal>#define HAVE_INTTYPES_H 1</literal>, etc.
The default is <literal>None</literal>,
which creates no configure header.
The convention has been to call
the configure header <filename>config.h</filename>.
You can specify the same
<parameter>config_h</parameter>
file in multiple calls to &Configure;,
in which case &SCons;
will concatenate all results in the specified file.
Note that &SCons;
uses its normal dependency tracking
to decide if it's necessary to rebuild the
configure hearer.
This means that the file is not necessarily rebuilt each
time scons is run,
but is only rebuilt if its contents will have changed
and some target that depends on the configure header is being built.
</para>

<para>The <parameter>clean</parameter>
and
<parameter>help</parameter>
arguments can be used to suppress execution of the configuration
tests when the
<option>-c</option>/<option>--clean</option>
or
<option>-H</option>/<option>-h</option>/<option>--help</option>
options are used, respectively.
The default behavior is always to execute
&configure_context; tests,
since the results of the tests may
affect the list of targets to be cleaned
or the help text.
If the configure tests do not affect these,
then you may add the
<option>clean=False</option>
or
<option>help=False</option>
arguments
(or both)
to avoid unnecessary test execution.</para>

<para>
<emphasis>Changed in version 4.0</emphasis>: raises an exception
on an attempt to create a new context when there is an active context.
</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>context</replaceable>.<methodname>Finish</methodname>()</term>
  <listitem>
<para>Must be called after configuration is complete.
Though required, this is not enforced except
if &Configure; is called again while there is still an active context,
in which case an exception is raised.
Returns the context's &consenv; as modified
during the course of running the configuration checks -
the original environment is unchanged;
typically the returned environment is used to
replace the original.
After this method is called, no further checks can be performed
with this configuration context.
However, you can create a new
&configure_context; to perform additional checks.
</para>
  </listitem>
  </varlistentry>
</variablelist>

<para>Example of a typical Configure usage:</para>

<programlisting language="python">
env = Environment()
conf = Configure(env)
if not conf.CheckCHeader("math.h"):
    print("We really need math.h!")
    Exit(1)
if conf.CheckLibWithHeader("qt", "qapp.h", "c++", call="QApplication qapp(0,0);"):
    # do stuff for qt - usage, e.g.
    conf.env.Append(CPPDEFINES="WITH_QT")
env = conf.Finish()
</programlisting>

<para>A &configure_context;
has the following predefined methods which
can be used to perform checks. Where
<parameter>language</parameter> is an optional parameter,
it specifies the programming language of the check,
currently a choice of C or C++.
The spellings accepted for
C are <quote>C</quote> or <quote>c</quote>;
for C++ the value can be
<quote>CXX</quote>, <quote>cxx</quote>, <quote>C++</quote>
or <quote>c++</quote>.
If <parameter>language</parameter> is omitted,
<quote>C</quote> is assumed.
</para>

<variablelist>
  <varlistentry id="conf-checkheader">
  <term><replaceable>context</replaceable>.<methodname>CheckHeader</methodname>(<parameter>header, [include_quotes, language]</parameter>)</term>
  <listitem>
<para>Check if
<parameter>header</parameter>
can be used when building this project.
A generated stub program in the specified
<parameter>language</parameter> is built to check.
<parameter>header</parameter> may also be a list,
in which case the last item in the list
is the header file to be checked,
and the previous list items are
header files whose
<literal>#include</literal>
directives should precede the
header line being checked for.
The optional argument
<parameter>include_quotes</parameter>
specifies the characters wrapping the header name -
only the first two are considered.
Essentially, this allows you to swap the default
double-quotes (<literal>""</literal>)
for angle brackets (<literal>&lt;&gt;</literal>).
</para>

<para>Returns a boolean indicating success or failure.
If a configure header was requested,
the result is recorded in it in the form of a
preprocessor macro in the case of success,
or an informative comment in the case of failure.
</para>

  </listitem>
  </varlistentry>

  <varlistentry id="check-checkcheader">
  <term><replaceable>context</replaceable>.<methodname>CheckCHeader</methodname>(<parameter>header, [include_quotes]</parameter>)</term>
  <listitem>
<para>Check if
<parameter>header</parameter>
is usable when compiling a C language program.
This is a wrapper around
<link linkend="conf-checheader">&CheckHeader;</link> -
see its entry for details.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="check-checkcxxheader">
  <term><replaceable>context</replaceable>.<methodname>CheckCXXHeader</methodname>(<parameter>header, [include_quotes]</parameter>)</term>
  <listitem>
<para>Check if
<parameter>header</parameter>
is usable when compiling a C++ language program.
This is a wrapper around
<link linkend="conf-checheader">&CheckHeader;</link> -
see its entry for details.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="check-checkfunc">
  <term><replaceable>context</replaceable>.<methodname>CheckFunc</methodname>(<parameter>function_name, [header, language, funcargs]</parameter>)</term>
  <listitem>
<para>Check if <parameter>function_name</parameter> is usable
in the context's local environment, using the compiler
specified by <parameter>language</parameter> - that is,
can a check referencing it be compiled using the current values
of &cv-link-CFLAGS;, &cv-link-CPPFLAGS;,
   &cv-link-LIBS; or other relevant &consvars;.
</para>

<para>
The optional
<parameter>header</parameter>
argument is a string representing a code fragment
to place at the top of the test program
that will be compiled to check if the function exists.
If omitted, the default stanza will be
(with <parameter>function_name</parameter> appropriately substituted):
</para>

<programlisting language="C">
#ifdef __cplusplus
extern "C"
#endif
char function_name(void);
</programlisting>

<para>
If <parameter>header</parameter> is supplied, it should <emphasis>not</emphasis> include
the standard header file that declares <parameter>function_name</parameter> and it
<emphasis>should</emphasis> include a dummy prototype similar to the default case.  If
this is not possible, the optional <parameter>funcargs</parameter> argument can be used
to specify a string containing an argument list with the same number and type of
arguments as the prototype.  The arguments can simply be constant values of the correct
type.  Modern C/C++ compilers reject implicit function declarations and may also reject
function calls whose arguments are not type compatible with the prototype.
</para>

<para>Returns a boolean indicating success or failure.
If a configure header was requested,
the result is recorded in it in the form of a
preprocessor macro in the case of success,
or an informative comment in the case of failure.
</para>

<para>
<emphasis>Changed in version 4.7.0: added the <parameter>funcargs</parameter>.</emphasis>
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="conf-checklib">
  <term><replaceable>context</replaceable>.<methodname>CheckLib</methodname>(<parameter>[library, symbol, header, language, extra_libs=None, autoadd=True, append=True, unique=False]</parameter>) </term>
  <listitem>
<para>Check if
<parameter>library</parameter>
can be used to build this project
(see also <link linkend="conf-checklibwithheader">&CheckLibWithHeader;</link>).
A small stub program is generated and linked against
<parameter>library</parameter> by the
compiler selected by <parameter>language</parameter>.
If <parameter>symbol</parameter> is specified,
the stub will contain a reference to that symbol,
to check if it is actually provided by the library.
If supplied, the text of <parameter>header</parameter>
is included at the top of the stub; it must be syntactically
correct in <parameter>language</parameter>.
</para>
<para>
Note that if <parameter>symbol</parameter> is given,
the stub will be generated with an old-style prototype,
as it has no knowledge of the actual prototype
(e.g. <code>char sin();</code> instead of
<code>double sin(double x);</code>).
Such usage is no longer legal under C23 and later.
</para>
<para>
The remaining arguments should be specified in keyword style.
If <parameter>extra_libs</parameter> is specified,
it is a list off additional libraries to include when
linking the stub program (usually, dependencies of
the library being checked).
If <parameter>autoadd</parameter> is true (the default),
and the link succeeds,
the library is added to the &cv-link-LIBS; &consvar; in the context.
If <parameter>append</parameter> is true (the default),
an added library is appended, otherwise it is prepended.
If <parameter>unique</parameter> is true,
and the library would otherwise be added but is
already present in &cv-link-LIBS; in the configure context,
it will not be added again. The default is <literal>False</literal>.
</para>
<para>
<parameter>library</parameter> can be a list of library names,
or <constant>None</constant> (the default if the argument is omitted).
If the former, <parameter>symbol</parameter> is checked against
each library name in order, returning
(and reporting success) on the first
successful test; if the latter,
it is checked with the current value of &cv-LIBS;
(in this case no library name would be added).
If <parameter>symbol</parameter>
is omitted or <constant>None</constant>,
then <function>CheckLib</function>
just checks if
you can link against the specified
<parameter>library</parameter>.
Note though it is legal syntax, it would
not be very useful to call this method
with <parameter>library</parameter>
and <parameter>symbol</parameter> both
omitted or <constant>None</constant> -
at least one should be supplied.
</para>
<para>Returns a boolean indicating success or failure.</para>
<para>
<emphasis>Changed in version 4.5.0: added the
<parameter>append</parameter> and <parameter>unique</parameter>
parameters.</emphasis>
</para>
<para>
<emphasis>Changed in version 4.9.0: added the
<parameter>extra_libs</parameter> parameter.</emphasis>
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="conf-checklibwithheader">
  <term><replaceable>context</replaceable>.<methodname>CheckLibWithHeader</methodname>(<parameter>[library, header, language, extra_libs=None, call=None, autoadd=True, append=True, unique=False]</parameter>)</term>
  <listitem>

<para>Check if
<parameter>library</parameter>
can be used to build this project,
when a header file must be included to use <parameter>library</parameter>
(see also <link linkend="conf-checklib">&CheckLib;</link>).
The first three arguments can be given as
either positional or keyword arguments.
<parameter>library</parameter>
specifies a library or list of libraries to check
(the default is <literal>None</literal>),
<parameter>header</parameter>
specifies a header file or list of header files to include in the test program.
If <parameter>header</parameter> is a list,
the last item in the list is the header file to be checked,
and the previous list items are
header files whose
<literal>#include</literal>
lines should precede the
header line being checked for.
The default is to include no header text.
</para>

<para>
The remaining parameters should be specified in keyword style.
If provided, <parameter>call</parameter>
is a code fragment to compile as the stub test,
replacing the auto-generated stub.
The fragment must be a valid expression in <parameter>language</parameter>.
If not supplied,
the default checks the ability to link against the specified
<parameter>library</parameter>.
<parameter>extra_libs</parameter> can be used to add additional libraries
to link against (usually, dependencies of the library under test).
If <parameter>autoadd</parameter> is true (the default),
the first library that passes the check
is added to the &cv-link-LIBS; &consvar; in the configure context
and the method returns.
If <parameter>append</parameter> is true (the default),
an added library is appended, otherwise it is prepended.
If <parameter>unique</parameter> is true,
and the library would otherwise be added but is
already present in &cv-link-LIBS; in the configure context,
it will not be added again. The default is <literal>False</literal>.
</para>

<para>Returns a boolean indicating success or failure.</para>

<para>
<emphasis>Changed in version 4.5.0: added the
<parameter>append</parameter> and <parameter>unique</parameter>
parameters.</emphasis>
</para>
<para>
<emphasis>Changed in version 4.9.0: added the
<parameter>extra_libs</parameter> parameter.</emphasis>
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="conf-checktype">
  <term><replaceable>context</replaceable>.<methodname>CheckType</methodname>(<parameter>type_name, [includes, language]</parameter>)</term>
  <listitem>
<para>Check whether <parameter>type_name</parameter>
is defined via a <literal>typedef</literal>.
<parameter>includes</parameter>
is a string containing one or more
<literal>#include</literal>
lines that will be placed at the top
of the stub program
that will be compiled to perform the check.
Returns a boolean indicating success or failure.
If a configure header was requested,
the result is recorded in it in the form of a
preprocessor macro in the case of success,
or an informative comment in the case of failure.
</para>

<para>Example:</para>

<programlisting language="python">
sconf.CheckType('foo_type', '#include "my_types.h"', 'C++')
</programlisting>

  </listitem>
  </varlistentry>

  <varlistentry id="conf-checktypesize">
  <term><replaceable>context</replaceable>.<methodname>CheckTypeSize</methodname>(<parameter>type_name, [header, language, expect]</parameter>)</term>
  <listitem>
<para>Check for the size of a type
<parameter>type_name</parameter>
defined via a <literal>typedef</literal> (or built in).
The optional
<parameter>header</parameter>
argument is a string
that will be
placed at the top
of the stub program
that will be compiled to perform the check -
the default is empty.
The check succeeds and returns the size of the type
if it is found, else zero.
If the optional
<parameter>expect</parameter>
(integer) parameter is given,
the check succeeds only if the
detected size matches it.
</para>

<para>Example:</para>

<programlisting language="python">
CheckTypeSize('short', expect=2)
</programlisting>

<para>will return the size <literal>2</literal> only if short is
actually two bytes.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="conf-checkcc">
  <term><replaceable>context</replaceable>.<methodname>CheckCC</methodname>()</term>
  <listitem>
<para>Check whether the C compiler
(as defined by the &cv-link-CC; &consvar;) works,
by trying to compile a small source file.
This provides a more rigorous check:
by default, &SCons; itself only detects if there is a program
with the correct name, not if it is a functioning compiler.
Returns a boolean indicating success or failure.</para>

<para>The test program will be built with the
same command line as the one used by the &b-link-Object; builder
for C source files, so by setting relevant &consvars;
it can be used to detect if particular compiler flags will
be accepted or rejected by the compiler.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="conf-checkcxx">
  <term><replaceable>context</replaceable>.<methodname>CheckCXX</methodname>()</term>
  <listitem>
<para>Check whether the C++ compiler
(as defined by the &cv-link-CXX; &consvar;) works,
by trying to compile a small source file.
This provides a more rigorous check:
by default, &SCons; itself only detects if there is a program
with the correct name, not if it is a functioning compiler.
Returns a boolean indicating success or failure.</para>

<para>The test program will be built with the
same command line as the one used by the &b-link-Object; builder
for C++ source files, so by setting relevant &consvars;
it can be used to detect if particular compiler flags will
be accepted or rejected by the compiler.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="conf-checkshcc">
  <term><replaceable>context</replaceable>.<methodname>CheckSHCC</methodname>()</term>
  <listitem>
<para>Check whether the shared-object C compiler (as defined by the
&cv-link-SHCC; &consvar;) works
by trying to compile a small source file.
This provides a more rigorous check:
by default, &SCons; itself only detects if there is a program
with the correct name, not if it is a functioning compiler.
Returns a boolean indicating success or failure.</para>

<para>The test program will be built with the
same command line as the one used by the &b-link-SharedObject; builder
for C source files, so by setting relevant &consvars;
it can be used to detect if particular compiler flags will
be accepted or rejected by the compiler.
Note this does not check whether a shared library/dll can
be created.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="conf-checkshcxx">
  <term><replaceable>context</replaceable>.<methodname>CheckSHCXX</methodname>()</term>
  <listitem>
<para>Check whether the shared-object C++ compiler (as defined by the
&cv-link-SHCXX; &consvar;)
works by trying to compile a small source file.
This provides a more rigorous check:
by default, &SCons; itself only detects if there is a program
with the correct name, not if it is a functioning compiler.
Returns a boolean indicating success or failure.</para>

<para>The test program will be built with the
same command line as the one used by the &b-link-SharedObject; builder
for C++ source files, so by setting relevant &consvars;
it can be used to detect if particular compiler flags will
be accepted or rejected by the compiler.
Note this does not check whether a shared library/dll can
be created.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="conf-checkprog">
  <term><replaceable>context</replaceable>.<methodname>CheckProg</methodname>(<parameter>prog_name</parameter>)</term>
  <listitem>
<para>Check if
<parameter>prog_name</parameter>
exists in the path &SCons; will use at build time.
(<replaceable>context</replaceable>.<varname>env['ENV']['PATH']</varname>).
Returns a string containing the path to the program,
or <constant>None</constant> on failure.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="conf-checkdeclaration">
  <term><replaceable>context</replaceable>.<methodname>CheckDeclaration</methodname>(<parameter>symbol, [includes, language]</parameter>)</term>
  <listitem>
<para>Check if the specified
<parameter>symbol</parameter>
is declared.
<parameter>includes</parameter>
is a string containing one or more
<literal>#include</literal>
lines that will be inserted into the program
that will be run to test for the existence of the symbol.
</para>
<para>Returns a boolean indicating success or failure.</para>
  </listitem>
  </varlistentry>

    <varlistentry id="conf-checkmember">
        <term><replaceable>context</replaceable>.<methodname>CheckMember</methodname>(<parameter>aggregate_member,
            [header, language]</parameter>)
        </term>
        <listitem>
            <para>Check for the existence of a member of the C/C++ struct or class.
                <parameter>aggregate_member</parameter>
                specifies the struct/class and member to check for.
                <parameter>header</parameter>
                is a string containing one or more
                <literal>#include</literal>
                lines that will be inserted into the program
                that will be run to test for the existence of the member.
                Example:
            </para>

            <programlisting language="python">
sconf.CheckMember('struct tm.tm_sec', '#include &lt;time.h&gt;')
            </programlisting>

            <para>
                Returns a boolean indicating success or failure.
            </para>

            <para><emphasis>Added in 4.4.0</emphasis>.</para>
        </listitem>
    </varlistentry>


    <varlistentry id="conf-checkdefine">
  <term><replaceable>context</replaceable>.<methodname>Define</methodname>(<parameter>symbol, [value, comment]</parameter>)</term>
  <listitem>
<para>This method does not check for anything, but rather forces
the definition of a preprocessor macro that will be added
to the configure header.
<parameter>name</parameter> is the macro's identifier.
If <parameter>value</parameter> is given,
it will be be used as the macro replacement value.
If <parameter>value</parameter> is a string and needs to
display with quotes, the quotes need to be included,
as in <literal>'"string"'</literal>
If the optional
<parameter>comment</parameter> is given,
it is inserted as a comment above the macro definition
(suitable comment marks will be added automatically).
This is analogous to using <constant>AC_DEFINE</constant> in &Autoconf;.
</para>

<para>Examples:</para>

<programlisting language="python">
env = Environment()
conf = Configure(env)

# Puts the following line in the config header file:
#    #define A_SYMBOL
conf.Define("A_SYMBOL")

# Puts the following line in the config header file:
#    #define A_SYMBOL 1
conf.Define("A_SYMBOL", 1)
</programlisting>


<para>Examples of quoting string values:</para>

<programlisting language="python">
env = Environment()
conf = Configure(env)

# Puts the following line in the config header file:
#    #define A_SYMBOL YA
conf.Define("A_SYMBOL", "YA")

# Puts the following line in the config header file:
#    #define A_SYMBOL "YA"
conf.Define("A_SYMBOL", '"YA"')
</programlisting>


<para>Example including comment:</para>

<programlisting language="python">
env = Environment()
conf = Configure(env)

# Puts the following lines in the config header file:
#    /* Set to 1 if you have a symbol */
#    #define A_SYMBOL 1
conf.Define("A_SYMBOL", 1, "Set to 1 if you have a symbol")
</programlisting>

  </listitem>
  </varlistentry>
</variablelist>

<para id="custom_checks" xreflabel="custom checks">
You can define your own custom checks
in addition to using the predefined checks.
To enable custom checks,
pass a dictionary to the &f-link-Configure; function
as the <parameter>custom_tests</parameter> parameter.
The dictionary maps the names of the checks
to the custom check callables
(either a &Python; function or an instance of a class implementing a
<methodname>__call__</methodname> method).
Each custom check will be called with a
a <classname>CheckContext</classname>
instance  as the first parameter followed by the remaining arguments,
which must be supplied by the user of the check.
A <classname>CheckContext</classname> is not the same as
a configure context; rather it is an instance of a class
which contains a configure context
(available as <replaceable>chk_ctx</replaceable>.<varname>sconf</varname>).
A <classname>CheckContext</classname>
provides the following methods which custom checks
can make use of::</para>

<variablelist>
  <varlistentry>
  <term><replaceable>chk_ctx</replaceable>.<methodname>Message</methodname>(<parameter>text</parameter>)</term>
  <listitem>

<para>Displays <parameter>text</parameter>
as an indicator of progress.
For example: <computeroutput>Checking for library X...</computeroutput>.
Usually called before the check is started.
</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>chk_ctx</replaceable>.<methodname>Result</methodname>(<parameter>res</parameter>)</term>
  <listitem>

<para>Displays a result message as an indicator of progress.
If <parameter>res</parameter> is an integer,
displays <computeroutput>yes</computeroutput>
if <parameter>res</parameter> evaluates true
or <computeroutput>no</computeroutput> if false.
If <parameter>res</parameter> is a string,
it is displayed as-is.
Usually called after the check has completed.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>chk_ctx</replaceable>.<methodname>TryCompile</methodname>(<parameter>text, extension=''</parameter>)</term>
  <listitem>
<para>Check if a file containing <parameter>text</parameter>
and given the specified <parameter>extension</parameter> (e.g.
<literal>'.c'</literal>)
can be compiled to an object file
using the environment's &b-link-Object; builder.
Returns a boolean indicating success or failure.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>chk_ctx</replaceable>.<methodname>TryLink</methodname>(<parameter>text, extension=''</parameter>)</term>
  <listitem>
<para>Check if a file containing <parameter>text</parameter>
and given the specified <parameter>extension</parameter> (e.g.
<literal>'.c'</literal>)
can be compiled to an executable program
using the environment's &b-link-Program; builder.
Returns a boolean indicating success or failure.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>chk_ctx</replaceable>.<methodname>TryRun</methodname>(<parameter>text, extension=''</parameter>)</term>
  <listitem>
<para>Check if a file containing <parameter>text</parameter>
and given the specified <parameter>extension</parameter> (e.g.
<literal>'.c'</literal>)
can be compiled to an excutable program
using the environment's &b-link-Program; builder and subsequently executed.
Execution is only attempted if the build succeeds.
If the program executes successfully
(that is, its return status is <literal>0</literal>),
a tuple <literal>(True, outputStr)</literal>
is returned, where <varname>outputStr</varname>
is the standard output of the program.
If the program fails execution
(its return status is non-zero),
then <literal>(False, '')</literal> is returned.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>chk_ctx</replaceable>.<methodname>TryAction</methodname>(<parameter>action, [text, extension='']</parameter>)</term>
  <listitem>
<para>Check if the specified
<parameter>action</parameter>
with an optional source file
(contents <parameter>text</parameter>,
given extension <parameter>extension</parameter>)
can be executed.
<parameter>action</parameter>
may be anything which can be converted to an
<link linkend="action_objects">Action Object</link>.
On success, a tuple
<literal>(True, outputStr)</literal>
is returned, where <varname>outputStr</varname>
is the content of the target file.
On failure
<literal>(False, '')</literal>
is returned.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>chk_ctx</replaceable>.<methodname>TryBuild</methodname>(<parameter>builder, [text, extension='']</parameter>)</term>
  <listitem>
<para>Low level implementation for testing specific builds;
the methods above are based on this method.
Given the Builder instance
<parameter>builder</parameter>
and the optional
<parameter>text</parameter>
of a source file with optional
<parameter>extension</parameter>,
returns a boolean indicating success or failure.
In addition,
<replaceable>chk_ctx</replaceable>.<varname>lastTarget</varname>
is set to the build target node if the build was successful.</para>
  </listitem>
  </varlistentry>
</variablelist>
<para>Example of implementing and using custom checks:</para>

<programlisting language="python">
def CheckQt(chk_ctx, qtdir):
    chk_ctx.Message('Checking for qt ...')
    lastLIBS = chk_ctx.env['LIBS']
    lastLIBPATH = chk_ctx.env['LIBPATH']
    lastCPPPATH = chk_ctx.env['CPPPATH']
    chk_ctx.env.Append(LIBS='qt', LIBPATH=qtdir + '/lib', CPPPATH=qtdir + '/include')
    ret = chk_ctx.TryLink(
        """\
#include &lt;qapp.h&gt;
int main(int argc, char **argv) {
  QApplication qapp(argc, argv);
  return 0;
}
"""
    )
    if not ret:
        chkctx.env.Replace(LIBS=lastLIBS, LIBPATH=lastLIBPATH, CPPPATH=lastCPPPATH)
    chkctx.Result(ret)
    return ret

env = Environment()
conf = Configure(env, custom_tests={'CheckQt': CheckQt})
if not conf.CheckQt('/usr/lib/qt'):
    print('We really need qt!')
    Exit(1)
env = conf.Finish()
</programlisting>

</refsect2>

<refsect2 id='commandline_construction_variables'>
<title>Command-Line Construction Variables</title>

<para>
&SCons; depends on information stored in &consvars; to
control how targets are built.
It is often necessary to pass
specialized information at build time
to override the variables in the build scripts.
This can be done through variable-assignment arguments
on the command line and/or in stored variable files.
</para>

<para>
For the case where you want to specify new
values for &consvars;,
&SCons; provides a <firstterm>&Variables;</firstterm>
object to simplify collecting those
and updating a &consenv; with the values.
This helps processing commands lines like this:
</para>

<screen>
<userinput>scons VARIABLE=foo OTHERVAR=bar</userinput>
</screen>

<para>
Variables supplied on the command line
can always be manually processed by iterating the
<link linkend="v-ARGUMENTS">&ARGUMENTS;</link> dictionary
or the <link linkend="v-ARGLIST">&ARGLIST;</link> list,
However, using a &Variables; object allows you to describe
anticipated variables,
perform necessary type conversion,
validate that values meet defined constraints,
and specify default values, help messages and aliases.
This provides a somewhat similar interface to option handling
(see &f-link-AddOption;).
A &Variables; object also allows
obtaining values from a saved variables file,
or from a custom dictionary in an &SConscript; file.
The processed variables can then be applied to the desired &consenv;.
</para>

<para>
Conceptually, command-line targets control what to build,
command-line variables (and variable files) control how to build,
and command-line options control how &SCons; operates
(although &SCons; does not enforce that separation).
</para>

<para>To obtain an object for manipulating variables,
call the &Variables; factory function:</para>

<variablelist>
  <varlistentry id="v-Variables">
  <term><function>Variables</function>([<parameter>files, [args]]</parameter>)</term>
  <listitem>
<para>If <parameter>files</parameter> is a filename or list of filenames,
they are executed as &Python; scripts
to set saved variables when the
<link linkend='v-Update'><function>Update</function></link>
method is called.
This allows the use of &Python; syntax in the assignments.
A variables file can be the result of an previous call to the
<link linkend='v-Save'>&Save;</link> method.
If <parameter>files</parameter> is not specified,
or the
<parameter>files</parameter>
argument is
<constant>None</constant>,
then no files will be processed.
Supplying <constant>None</constant> is required
if there are no files but you want to specify
<parameter>args</parameter> as a positional argument;
or you can use keyword arguments to avoid that.
If any of <parameter>files</parameter> is missing,
it is silently skipped.
</para>

<para>
Either of the following example file
contents could be used to set an alternative C compiler:</para>

<programlisting language="python">
CC = 'my_cc'
CC = os.environ.get('CC')
</programlisting>

<para>If
<parameter>args</parameter>
is specified, it must be a dictionary.
The key-value pairs from <parameter>args</parameter>
will be added to those obtained from
<parameter>files</parameter>, if any.
Keys from <parameter>args</parameter>
take precedence over same-named keys from <parameter>files</parameter>.
If omitted, the default is the
<link linkend="v-ARGUMENTS">&ARGUMENTS;</link>
dictionary that holds build variables
specified on the command line.
Using &ARGUMENTS; allows you to indicate that if a setting appears
on both the command line and in the file(s),
the command line setting is preferred.
However, any dictionary can be passed.
Examples:</para>

<programlisting language="python">
vars = Variables('custom.py')
vars = Variables('overrides.py', ARGUMENTS)
vars = Variables(None, {FOO:'expansion', BAR:7})
vars = Variables(args={FOO:'expansion', BAR:7})
</programlisting>

<para>
Calling &Variables; with no arguments is equivalent to:
</para>
<programlisting language="python">
vars = Variables(files=None, args=ARGUMENTS)
</programlisting>

  </listitem>
  </varlistentry>
</variablelist>

<para>
A &Variables; object is a container for variable descriptions,
added by calling the
<link linkend='v-Add'><function>Add</function></link> or
<link linkend='v-AddVariables'><function>AddVariables</function></link>
methods.
A variable description consists of a name,
a list of aliases for the name,
a help message, a default value,
and functions to validate and convert values.
Processing of input sources is deferred until the
<link linkend='v-Update'><function>Update</function></link>
method is called,
at which time the variables are added to the
specified &consenv;,
using the name as the &consvar; name;
any aliases are not added.
Variables from the input sources which do not match any
names or aliases from the variable descriptions in this object are skipped,
except that a dictionary of their names and values are made available in the
<link linkend='v-unknown'><varname>unknown</varname></link>
attribute of the &Variables; object.
This list can also be obtained via the
<link linkend='v-UnknownVariables'><function>UnknownVariables</function></link>
method.
If a variable description has a default value
other than <literal>None</literal> and does not
appear in the input sources,
it is added to the &consenv; with its default value.
A list of variables set from their defaults and
not from the input sources is available as the
<link linkend='v-defaulted'><varname>defaulted</varname></link>
attribute of the &Variables; object.
The unknown variables and defaulted information is
not available until the &Update; method has run.
</para>

<para>
Since the variables are eventually added as &consvars;,
you should choose variable names which do not unintentionally change
pre-defined &consvars; that your project will make use of
(see <xref linkend="construction_variables"/> for a reference),
since the specified values are assigned, not merged,
to the respective &consvars;.
</para>

<para>
The &Variables; subsystem does not directly support a way
to define a variable the user <emphasis>must</emphasis> supply,
but this can be simulated by using a validator function,
and specifying a default value which the validator will reject,
resulting in an invalid value error message
(the convenience methods &EnumVariable; and
&ListVariable; make this relatively straightforward).
</para>

<para>A &Variables; object has the following methods:</para>

<variablelist>
  <varlistentry id="v-Add">
  <term><replaceable>vars</replaceable>.<function>Add</function>(<parameter>key, [help, default, validator, converter, subst]</parameter>)</term>
  <listitem>
<para>Add a customizable &consvar; to the &Variables; object.
<parameter>key</parameter>
is either the name of the variable,
or a sequence of strings, in which case
the first item in the sequence is taken as the variable name,
and any remaining values are considered aliases for the variable.
<parameter>key</parameter> is mandatory,
the other fields are optional.
<parameter>help</parameter>
is the help text for the variable
(defaults to an empty string).
<parameter>default</parameter>
is the default value of the variable
(defaults to <constant>None</constant>).
The variable will be set to the value of
<parameter>default</parameter> if it does
not appear in the input sources,
except if <parameter>default</parameter>
is <literal>None</literal>,
in which case it is not added to the &consenv;
unless it has been set in the input sources.
</para>

<para>
If the <parameter>validator</parameter> argument is supplied,
it is a callback function to validate the value of the variable
when the variables are processed
(that is, when the <link linkend='v-Update'>&Update;</link>
method runs).
A validator function must accept three arguments:
<parameter>key</parameter>,
<parameter>value</parameter>
and <parameter>env</parameter>,
and should raise an exception (with a helpful error message)
if <parameter>value</parameter> is invalid.
No return value is expected from the validator.
</para>

<para>
If the <parameter>converter</parameter> argument is supplied,
it is a callback function to convert the value into
one suitable for adding to the &consenv;.
A converter function must accept the
<parameter>value</parameter> argument,
and may declare <parameter>env</parameter>
as a second argument if it needs access to the
&consenv; while validating - the function will be called appropriately.
The converter is called before the validator;
it must return a value, which is then passed to the
<parameter>validator</parameter> (if any) for checking.
In general, the converter should not fail,
leaving validation checks to the validator,
although if an operation is impossible to complete
or there is no separate validator
it can raise a <exceptionname>ValueError</exceptionname>.
</para>

<para>
Substitution will be performed on the variable value
before the converter and validator are called,
unless the optional <parameter>subst</parameter> parameter
is false (the default is <literal>True</literal>).
Suppressing substitution may be useful if the variable value
looks like a &consvar; reference (e.g. <literal>$VAR</literal>)
and the validator and/or converter should see it unexpanded.
</para>

<para>
As a special case, if <parameter>key</parameter>
is a sequence and is the <emphasis>only</emphasis>
argument to &Add;, it is unpacked into the five parameters
<parameter>key</parameter>,
<parameter>help</parameter>,
<parameter>default</parameter>,
<parameter>validator</parameter> and
<parameter>converter</parameter>,
with any missing members from the right filled in with
the respective default values.
This form allows it
to consume a tuple emitted by the convenience functions
<link linkend='v-BoolVariable'>&BoolVariable;</link>,
<link linkend='v-EnumVariable'>&EnumVariable;</link>,
<link linkend='v-ListVariable'>&ListVariable;</link>,
<link linkend='v-PackageVariable'>&PackageVariable;</link>
and
<link linkend='v-PathVariable'>&PathVariable;</link>.
</para>

<para>Examples:</para>

<programlisting language="python">
vars.Add('CC', help='The C compiler')

def valid_color(key, val, env):
    if not val in ['red', 'blue', 'yellow']:
        raise Exception("Invalid color value '%s'" % val)

vars.Add('COLOR', validator=valid_color)
</programlisting>

<para>
<emphasis>Changed in version 4.8.0:</emphasis>
added the <parameter>subst</parameter> parameter.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="v-AddVariables">
  <term><replaceable>vars</replaceable>.<function>AddVariables</function>(<parameter>args</parameter>)</term>
  <listitem>
<para>A convenience method that adds
one or more customizable &consvars;
to a &Variables; object in one call;
equivalent to calling
<link linkend='v-Add'><function>Add</function></link>
multiple times.
Each <parameter>args</parameter> member
must be a tuple that contains the arguments
for an individual call to the &Add; method
using the "special case" form;
the other calling styles (individual positional
arguments and/or keyword arguments) are not supported.
</para>

<programlisting language="python">
opt.AddVariables(
    ("debug", "", 0),
    ("CC", "The C compiler"),
    ("VALIDATE", "An option for testing validation", "notset", validator, None),
)
</programlisting>

  </listitem>
  </varlistentry>

  <varlistentry id="v-FormatVariableHelpText">
  <term><replaceable>vars</replaceable>.<function>FormatVariableHelpText</function>(<parameter>env, opt, help, default, actual, aliases</parameter>)</term>
  <listitem>
<para>Returns a formatted string
containing the printable help text
for the single variable <parameter>opt</parameter>.
All of the arguments must be supplied
except <parameter>aliases</parameter>, which is optional.
<parameter>env</parameter>
is the &consenv; containing the variable values,
(<parameter>env</parameter> is not used by the standard
implementation of <function>FormatVariableHelpText</function>);
<parameter>var</parameter>
is the name of the variable;
<parameter>help</parameter>
is the text of the initial help message when the variable was
added to the &Variables; object;
<parameter>default</parameter>
is the default value assigned when the variable was added
to the &Variables; object;
<parameter>actual</parameter>
is the value as assigned in <parameter>env</parameter>
(which may be the same as <parameter>default</parameter>,
if none of the input sources assign to the variable);
and <parameter>aliases</parameter>
are any alias names for the variable,
if omitted defaults to an empty list.
</para>

<para>
<function>FormatVariableHelpText</function>
is normally not called directly, but by
&GenerateHelpText;, which does the work of
obtaining the necessary values.
You can patch in your own
function that takes the same function signature
in order to customize the appearance of variable help messages.
Example:
</para>

<programlisting language="python">
def my_format(env, var, help, default, actual):
    fmt = "\n%s: default=%s actual=%s (%s)\n"
    return fmt % (var, default, actual, help)

vars.FormatVariableHelpText = my_format
</programlisting>

<para>
Note that &GenerateHelpText;
will not put any blank lines or extra
characters between the entries,
so you must add those characters to the returned
string if you want the entries separated.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="v-GenerateHelpText">
  <term><replaceable>vars</replaceable>.<function>GenerateHelpText</function>(<parameter>env, [sort]</parameter>)</term>
  <listitem>
<para>
Return a formatted string with the help text collected
from all the variables configured in this &Variables; object.
This string is suitable for passing in to the &f-link-Help; function.
The generated string include an indication of the
actual value in the environment given by <parameter>env</parameter>.
</para>

<para>
If the optional
<parameter>sort</parameter> parameter is set to
a callable value, it is used as a comparison function to
determine how to sort the added variables.
This function must accept two arguments, compare them,
and return a negative integer if the first is
less-than the second, zero if equal, or a positive integer
if greater-than.
If <parameter>sort</parameter> is not callable,
but evaluates true,
an alphabetical sort is performed.
The default is <constant>False</constant> (unsorted).
</para>

<programlisting language="python">
Help(vars.GenerateHelpText(env))

def cmp(a, b):
    return (a &gt; b) - (a &lt; b)

Help(vars.GenerateHelpText(env, sort=cmp))
</programlisting>

  </listitem>
  </varlistentry>

  <varlistentry id="v-Save">
  <term><replaceable>vars</replaceable>.<function>Save</function>(<parameter>filename, env</parameter>)</term>
  <listitem>
<para>Saves the currently set variables into a script file named
by <parameter>filename</parameter>.
This provides a way to cache particular variable settings for reuse.
Only variables that are set to non-default values are saved.
You can load these saved variables on a subsequent run
by passing <parameter>filename</parameter> to the
<link linkend='v-Variables'>&Variables;</link> function,

</para>

<programlisting language="python">
env = Environment()
vars = Variables(['variables.cache', 'custom.py'])
vars.Add(...)
vars.Update(env)
vars.Save('variables.cache', env)
</programlisting>

  </listitem>
  </varlistentry>

  <varlistentry id="v-UnknownVariables">
  <term><replaceable>vars</replaceable>.<function>UnknownVariables</function>()</term>
  <listitem>
<para>Returns a dictionary containing any
variables that were specified in the
<parameter>files</parameter> and/or
<parameter>args</parameter> parameters
when <link linkend='v-Variables'>&Variables;</link>
was called, but the object was not actually configured for.
This information is not available until the
<link linkend='v-Update'><function>Update</function></link>
method has run.
</para>

<programlisting language="python">
env = Environment(variables=vars)
for key, value in vars.UnknownVariables():
    print("unknown variable:  %s=%s" % (key, value))
</programlisting>

  </listitem>
  </varlistentry>

  <varlistentry id="v-Update">
  <term><replaceable>vars</replaceable>.<function>Update</function>(<parameter>env, [args]</parameter>)</term>
  <listitem>
<para>Process the input sources recorded
when the &Variables; object was initialized
and update
<parameter>env</parameter>
with the customized &consvars;.
The names of any variables in the input sources that are not
configured in the &Variables; object
are recorded and may be retrieved using the
<link linkend='v-UnknownVariables'>&UnknownVariables;</link>
method.</para>

<para>
If the optional
<parameter>args</parameter>
argument is provided, it must be a dictionary of variables,
which will be used in place of the one saved when the
<link linkend='v-Variables'>&Variables;</link> object
was created.
</para>

<para>Normally, &Update; is not called directly,
but rather invoked indirectly by passing the &Variables; object to
the &f-link-Environment; function:</para>

<programlisting language="python">
env = Environment(..., variables=vars)
</programlisting>

  </listitem>
  </varlistentry>
</variablelist>

<para>
A &Variables; object also makes available two data attributes
that can be read for further information. These only have
values if <link linkend='v-Update'><function>Update</function></link>
has previously run.
</para>

<variablelist>
  <varlistentry id="v-defaulted">
  <term><replaceable>vars</replaceable>.<parameter>defaulted</parameter></term>
  <listitem>
<para>
A list of variable names that were set in the &consenv;
from the default values in the variable descriptions -
that is, variables that have a default value and were
not defined in the input sources.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="v-unknown">
  <term><replaceable>vars</replaceable>.<parameter>unknown</parameter></term>
  <listitem>
<para>
A dictionary of variables that were specified in the input sources,
but do not have matching variable definitions.
This is the same information that is returned by the
<link linkend='v-UnknownVariables'>&UnknownVariables;</link> method.
</para>
  </listitem>
  </varlistentry>
</variablelist>
<para><emphasis>Added in 4.9.0</emphasis>:
the <parameter>defaulted</parameter> attribute.
</para>

<para>
&SCons; provides five pre-defined variable types,
accessible through factory functions that generate
a tuple appropriate for directly passing to the
<link linkend='v-Add'><function>Add</function></link> or
<link linkend='v-AddVariables'><function>AddVariables</function></link>
methods.
</para>

<variablelist>
  <varlistentry id="v-BoolVariable">
  <term><function>BoolVariable</function>(<parameter>key, help, default</parameter>)</term>
  <listitem>
<para>
Set up a Boolean variable named <parameter>key</parameter>.
The variable will have a default value of
<parameter>default</parameter>,
and <parameter>help</parameter>
will form the descriptive part of the help text.
The variable will interpret the command-line values
<userinput>y</userinput>,
<userinput>yes</userinput>,
<userinput>t</userinput>,
<userinput>true</userinput>,
<userinput>1</userinput>,
<userinput>on</userinput>
and
<userinput>all</userinput>
as true,
and the command-line values
<userinput>n</userinput>,
<userinput>no</userinput>,
<userinput>f</userinput>,
<userinput>false</userinput>,
<userinput>0</userinput>,
<userinput>off</userinput>
and
<userinput>none</userinput>
as false.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="v-EnumVariable">
  <term><function>EnumVariable</function>(<parameter>key, help, default, allowed_values, [map, ignorecase]</parameter>)</term>
  <listitem>
<para>
Set up a variable named <parameter>key</parameter>
whose value may only be chosen from
a specified list ("enumeration") of values.
The variable will have a default value of
<parameter>default</parameter>
and <parameter>help</parameter>
will form the descriptive part of the help text.
Any value that is not in
<parameter>allowed_values</parameter>
will raise an error,
except that the optional
<parameter>map</parameter>
argument is a dictionary
that can be used to map additional names into
a particular name in the
<parameter>allowed_values</parameter> list.
If the optional
<parameter>ignorecase</parameter> is <literal>0</literal> (the default),
the values are considered case-sensitive.
If <parameter>ignorecase</parameter> is <literal>1</literal>,
values will be matched
case-insensitively.
If <parameter>ignorecase</parameter> is <literal>2</literal>,
values will be matched
case-insensitively,
and all input values will be
converted to lower case.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="v-ListVariable">
  <term><function>ListVariable</function>(<parameter>key, help, default, names, [map, validator]</parameter>)</term>
  <listitem>
<para>
Set up a variable named <parameter>key</parameter>
whose value may be one or more choices
from a specified list of values.
The variable will have a default value of
<parameter>default</parameter>,
and <parameter>help</parameter>
will form the descriptive part of the help text.
Any value that is not in
<parameter>names</parameter> or the special values
<userinput>all</userinput> or
<userinput>none</userinput>
will raise an error.
Use a comma separator to specify multiple values.
<parameter>default</parameter> may be specified
either as a string of comma-separated values,
or as a &Python; list of values.
</para>
<para>
The optional
<parameter>map</parameter>
argument is a dictionary
that can be used to convert
input values into specific legal values
in the
<parameter>names</parameter>
list.
(Note that the additional values accepted through
the use of a <parameter>map</parameter> are not
reflected in the generated help message).  </para>
<para>
The optional <parameter>validator</parameter> argument
can be used to specify a custom validator callback function,
as described for <link linkend='v-Add'><function>Add</function></link>.
The default is to use an internal validator routine.
</para>
<para><emphasis>Added in 4.8.0</emphasis>:
the <parameter>validator</parameter> parameter.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="v-PackageVariable">
  <term><function>PackageVariable</function>(<parameter>key, help, default</parameter>)</term>
  <listitem>
<para>
Set up a variable named <parameter>key</parameter>
to help control a build component,
such as a software package.
Similar to a
<link linkend='v-BoolVariable'><function>BoolVariable</function></link>,
but can also specify a path string
to provide additional information to the build,
for example the path to a configuration file describing the package,
or a directory containing the package headers and libraries.
The variable will have a default value of
<parameter>default</parameter>,
and the <parameter>help</parameter> parameter
will be used as the descriptive part of the help text.
</para>

<para>
Any of the (case-insensitive) strings
<userinput>1</userinput>,
<userinput>yes</userinput>,
<userinput>true</userinput>,
<userinput>on</userinput>,
<userinput>enable</userinput>
or
<userinput>search</userinput>
can be used to indicate the package is "enabled",
and can also be used as the value of <parameter>default</parameter>.
A value of boolean <constant>True</constant> is
produced except for the special case described
for a path string.
</para>

<para>
Any of the (case-insensitive) strings
<userinput>0</userinput>,
<userinput>no</userinput>,
<userinput>false</userinput>,
<userinput>off</userinput>
or
<userinput>disable</userinput>
can be used to indicate the package is "disabled",
and can also be used as the value of <parameter>default</parameter>.
A value of boolean <constant>False</constant> is
produced.
</para>

<para>
A string which is neither an enabling or disabling
string is considered a "path string".
A path string can be given when specifying the variable,
and can also be used as the value of <parameter>default</parameter>.
A path string must refer to an existing filesystem path,
but any further meaning is left to the build system to decide.
The path string is produced.
As a special case,
if <parameter>default</parameter> is a path string,
and the variable is specified with an enabling string,
the default path string is produced,
rather than <literal>True</literal>.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="v-PathVariable">
  <term><function>PathVariable</function>(<parameter>key, help, default, [validator]</parameter>)</term>
  <listitem>
<para>
Set up a variable named <parameter>key</parameter> to hold a path string.
The variable will have a default value of
<parameter>default</parameter>,
and the <parameter>help</parameter> parameter
will be used as the descriptive part of the help text.
</para>

<para>
The optional
<parameter>validator</parameter> parameter
describes a callback function which will be called to
verify that the specified path is acceptable.
SCons supplies the
following ready-made validators:</para>

  <variablelist>  <!-- nested list -->
  <varlistentry>
    <term><literal>PathVariable</literal>.<function>PathExists</function></term>
    <listitem>
<para>Verify that the specified path exists
(this the default behavior if no
<parameter>validator</parameter> is supplied).</para>
    </listitem>
  </varlistentry>

  <varlistentry>
    <term><literal>PathVariable</literal>.<function>PathIsFile</function></term>
    <listitem>
<para>Verify that the specified path exists and is a regular file.</para>
    </listitem>
  </varlistentry>

  <varlistentry>
    <term><literal>PathVariable</literal>.<function>PathIsDir</function></term>
    <listitem>
<para>Verify that the specified path exists and is a directory.</para>
    </listitem>
  </varlistentry>

  <varlistentry>
    <term><literal>PathVariable</literal>.<function>PathIsDirCreate</function></term>
    <listitem>
<para>Verify that the specified path exists and is a directory;
if it does not exist, create the directory.</para>
    </listitem>
  </varlistentry>

  <varlistentry>
    <term><literal>PathVariable</literal>.<function>PathAccept</function></term>
    <listitem>
<para>Accept the specific path name argument without validation,
suitable for when you want your users
to be able to specify a directory path that will be
created as part of the build process, for example.</para>
    </listitem>
  </varlistentry>
  </variablelist>  <!-- end nested list -->

<para>
You may supply your own
<emphasis>validator</emphasis>
function,
which must accept three arguments:
<parameter>key</parameter>,
the name of the variable to be set;
<parameter>val</parameter>,
the specified value being checked;
and
<parameter>env</parameter>,
the &consenv;,
and should raise an exception
if the specified value is not acceptable.</para>
  </listitem>
  </varlistentry>
</variablelist>
<para>These functions make it
convenient to create a number
of variables with consistent behavior
in a single call to the
<link linkend='v-AddVariables'><function>AddVariables</function></link>
method:
</para>

<programlisting language="python">
vars.AddVariables(
    BoolVariable(
        "warnings",
        help="compilation with -Wall and similar",
        default=True,
    ),
    EnumVariable(
        "debug",
        help="debug output and symbols",
        default="no",
        allowed_values=("yes", "no", "full"),
        map={},
        ignorecase=0,  # case-sensitive
    ),
    ListVariable(
        "shared",
        help="libraries to build as shared libraries",
        default="all",
        names=list_of_libs,
    ),
    PackageVariable(
        "x11",
        help="use X11 installed here (yes = search some places)",
        default="yes",
    ),
    PathVariable(
        "qtdir",
        help="where the root of Qt is installed",
        default=qtdir
    ),
    PathVariable(
        "foopath",
        help="where the foo library is installed",
        default=foopath,
        validator=PathVariable.PathIsDir,
    ),
)
</programlisting>

</refsect2>

<refsect2 id='node_objects'>
<title>Node Objects</title>

<para>
&SCons; represents objects that are the sources or targets of
build operations as <firstterm>Nodes</firstterm>,
which are internal data structures.
There are a number of user-visible types of nodes:
File Nodes, Directory Nodes, Value Nodes and Alias Nodes.
Some of the node types have public attributes and methods,
described below. Each of the node types has a global function
and a matching environment method to create instances:
&f-link-File;, &f-link-Dir;, &f-link-Value; and &f-link-Alias;.
</para>

<refsect3 id='file_and_directory_nodes'>
<title>Filesystem Nodes</title>

<para>
The &f-link-File; and &f-link-Dir;
functions/methods return
File Nodes and Directory Nodes, respectively.
Such <firstterm>Filesystem Nodes</firstterm>
represent build components that correspond to an entry
in the computer's filesystem,
whether or not such an entry exists at the time the Node is created.
You do not usually need to explicitly create filesystem Nodes,
since when you supply a string as a target or source of a Builder,
&SCons; will create the Nodes as needed to populate the
dependency graph.
Builders return the target Node(s) in the form of a list,
which you can then make use of.
However, since filesystem Nodes have some useful
public attributes and methods
that you can use in &SConscript; files,
it is sometimes appropriate to create them manually,
outside the regular context of a Builder call.
</para>
<para>
The following attributes provide information about a Node:
</para>

<variablelist>
  <varlistentry>
  <term><replaceable>node</replaceable>.<varname>path</varname></term>
  <listitem>
<para>The build path
of the given file or directory.
This path is relative to the project top directory.
The build path is the same as the source path if
<emphasis>variant_dir</emphasis>
is not being used.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>node</replaceable>.<varname>abspath</varname></term>
  <listitem>
<para>The absolute build path of the given file or directory.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>node</replaceable>.<varname>relpath</varname></term>
  <listitem>
<para>The build path of the given file or directory relative to
the project top directory.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>node</replaceable>.<function>srcnode</function>()</term>
  <listitem>
<para>The
<function>srcnode</function>
method
returns another File or Directory Node
representing the source path of the given
File or Directory Node.
</para>
  </listitem>
  </varlistentry>
</variablelist>

<para>Examples:</para>

<programlisting language="python">
# Get the current build dir's path, relative to top.
Dir('.').path

# Current dir's absolute path
Dir('.').abspath

# Current dir's path relative to the project top directory
Dir('.').relpath

# Next line is always '.', because it is the top dir's path relative to itself.
Dir('#.').path

# Source path of the given source file.
File('foo.c').srcnode().path

# Builders return lists of File objects:
foo = env.Program('foo.c')
print("foo will be built in", foo[0].path)
</programlisting>

<para>
Filesystem Node objects have methods to create new
Filesystem Nodes relative to the original Node.
There are also times when you may need to refer to an entry
in a filesystem without knowing in advance whether it's a
file or a directory.
For those situations,
there is an <function>Entry</function> method of filesystem node objects,
which returns a Node that can represent either a file or a directory.
</para>

<para>
If the original Node is a Directory Node,
these methods will place the new Node within the directory
the original Node represents:
</para>

<variablelist>
  <varlistentry>
  <term><replaceable>node</replaceable>.<function>Dir</function>(<parameter>name</parameter>)</term>
  <listitem>
<para>Returns a directory Node
<parameter>name</parameter>
which is a subdirectory of
the directory represented by
<replaceable>node</replaceable>.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>node</replaceable>.<function>File</function>(<parameter>name</parameter>)</term>
  <listitem>
<para>Returns a file Node
<parameter>name</parameter>
in the directory represented by
<replaceable>node</replaceable>.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>node</replaceable>.<function>Entry</function>(<parameter>name</parameter>)</term>
  <listitem>
<para>Returns an unresolved Node
<parameter>name</parameter>
in the directory represented by
<replaceable>node</replaceable>.</para>
  </listitem>
  </varlistentry>
</variablelist>

<para>
If the original Node is a File Node,
these methods will place the new Node in the same
directory as the one the original Node represents:
</para>

<variablelist>
  <varlistentry>
  <term><replaceable>node</replaceable>.<function>Dir</function>(<parameter>name</parameter>)</term>
  <listitem>
<para>Returns a Node
<parameter>name</parameter>
for a directory in the parent directory of
the file represented by
<replaceable>node</replaceable>.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>node</replaceable>.<function>File</function>(<parameter>name</parameter>)</term>
  <listitem>
<para>Returns a Node
<parameter>name</parameter>
for a file in the parent directory of
the file represented by
<replaceable>node</replaceable>.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><replaceable>node</replaceable>.<function>Entry</function>(<parameter>name</parameter>)</term>
  <listitem>
<para>Returns an unresolved Node
<parameter>name</parameter>
in the parent directory of
the file represented by
<replaceable>node</replaceable>.</para>
  </listitem>
  </varlistentry>
</variablelist>

<para>For example:</para>

<programlisting language="python">
# Get a Node for a file within a directory
incl = Dir('include')
f = incl.File('header.h')

# Get a Node for a subdirectory within a directory
dist = Dir('project-3.2.1')
src = dist.Dir('src')

# Get a Node for a file in the same directory
cfile = File('sample.c')
hfile = cfile.File('sample.h')

# Combined example
docs = Dir('docs')
html = docs.Dir('html')
index = html.File('index.html')
css = index.File('app.css')
</programlisting>
</refsect3>

<refsect3 id='value_and_alias_nodes'>
<title>Value and Alias Nodes</title>

<para>
&SCons; provides two other Node types to represent
object that will not have an equivalent filesystem entry.
Such Nodes always need to be created explicitly.
</para>

<para>
The &f-link-Alias; method returns an Alias Node.
Aliases are virtual objects - they will not themselves result
in physical objects being constructed, but are entered into
the dependency graph related to their sources.
An alias is checked for up to date by checking if
its sources are up-to-date.
An alias is built by making sure its sources have been built,
and if any building took place,
applying any Actions that are defined as part of the alias.
</para>

<para>
An &f-link-Alias; call creates an entry in the alias namespace,
which is used for disambiguation.
If an alias source has a string valued name,
it will be resolved to a filesystem entry Node,
unless it is found in the alias namespace,
in which case it is resolved to the matching alias Node.
As a result, the order of &f-Alias; calls is significant.
An alias can refer to another alias, but only if the
other alias has previously been created.
</para>

<para>
The &f-link-Value; method returns a Value Node.
Value nodes are often used for generated data that
will not have any corresponding filesystem entry,
but will be used to determine whether a build target is out-of-date,
or to include as part of a build Action.
Common examples are timestamp strings,
revision control version strings
and other run-time generated strings.
</para>

<para>
A Value Node can also be the target of a builder.
</para>
</refsect3>

</refsect2>
</refsect1>

<refsect1 id='extending_scons'>
<title>EXTENDING SCONS</title>

<para>
&SCons; is designed to be extensible through provided facilities,
so changing the code of &SCons; itself is only rarely needed
to customize its behavior.
A number of the main operations use callable objects
which can be supplemented by writing your own.
Builders, Scanners and Tools each use a kind of plugin system,
allowing you to easily drop in new ones.
Information about creating
<link linkend='builder_objects'>Builder Objects</link> and
<link linkend='scanner_objects'>Scanner Objects</link>
appear in the following sections.
The instructions &SCons; actually uses to
construct things are called Actions,
and it is easy to create Action Objects and hand them
to the objects that need to know about those actions
(besides Builders, see &f-link-AddPostAction;,
&f-link-AddPreAction; and &f-link-Alias; for some examples
of other places that take Actions).
<link linkend='action_objects'>Action Objects</link>
are also described below.
Adding new Tool modules is described in
<link linkend='tool_modules'>Tool Modules</link>
</para>

<refsect2 id='builder_objects'>
<title>Builder Objects</title>

<para>&scons;
can be extended to build additional types of targets
by adding new Builder objects
to a &consenv;.
<emphasis>In general</emphasis>,
you should only need to add a new Builder object
when you want to build a new type of file or other external target.
For output file types &scons; already knows about,
you can usually modify the behavior of premade Builders
such as &b-link-Program;, &b-link-Object; or &b-link-Library;
by changing the &consvars; that control their behavior
(&cv-link-CC;, &cv-link-LINK;, etc.).
In this manner you can, for example, change the compiler to use,
which is simpler and less error-prone than writing a new builder.
The documentation for each Builder lists which
&consvars; it uses.
</para>

<para>Builder objects are created
using the
&f-link-Builder;
factory function.
Once created, a builder is added to a &consenv;
by registering it in the &cv-link-BUILDERS; dictionary
in that environment (some of the examples
in this section illustrate this).
Doing so automatically triggers &SCons; to add a method
with the name of the builder to the environment.
</para>

<para>
The
&f-Builder;
function accepts the following keyword arguments:</para>

<variablelist>
  <varlistentry>
  <term><parameter>action</parameter></term>
  <listitem>
<para>The command used to build the target from the source.
<parameter>action</parameter>
may be a string representing a template command line to execute,
a list of strings representing the command
to execute with its arguments
(suitable for enclosing white space in an argument),
a dictionary
mapping source file name suffixes to
any combination of command line strings
(if the builder should accept multiple source file extensions),
a &Python; function,
an Action object
(see <link linkend='action_objects'>Action Objects</link>)
or a list of any of the above.</para>

<para>An action function must accept three arguments:
<parameter>source</parameter>,
<parameter>target</parameter> and
<parameter>env</parameter>.
<parameter>source</parameter> is a list of source nodes;
<parameter>target</parameter> is a list of target nodes;
<parameter>env</parameter> is the &consenv; to use for context.
</para>

<para>
The <parameter>action</parameter>
and <parameter>generator</parameter>
arguments must not both be used for the same Builder.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>prefix</parameter></term>
  <listitem>
<para>The prefix to prepend to the target file name.
<parameter>prefix</parameter> may be
a string, a function (or other callable) that takes
two arguments (a &consenv; and a list of sources)
and returns a prefix string,
or a dictionary specifying a mapping from a specific source suffix
(of the first source specified)
to a corresponding target prefix string.  For the dictionary form, both the source
suffix (key) and target prefix (value) specifications may use environment variable
substitution, and the target prefix
may also be a callable object.  The default target prefix
may be indicated by a dictionary entry with a key of <constant>None</constant>.</para>

<programlisting language="python">
b = Builder("build_it &lt; $SOURCE &gt; $TARGET", prefix="file-")

def gen_prefix(env, sources):
    return "file-" + env['PLATFORM'] + '-'

b = Builder("build_it &lt; $SOURCE &gt; $TARGET", prefix=gen_prefix)

b = Builder(
    "build_it &lt; $SOURCE &gt; $TARGET",
    suffix={None: "file-", "$SRC_SFX_A": gen_prefix},
)
</programlisting>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>suffix</parameter></term>
  <listitem>
<para>The suffix to append to the target file name.
Specified in the same manner as for <parameter>prefix</parameter> above.
If the suffix is a string, then
&scons;
prepends a <literal>'.'</literal> to the suffix if it's not already there.
The string returned by the callable object or obtained from the
dictionary is untouched, and you need to manually prepend a <literal>'.'</literal>
if one is required.</para>

<programlisting language="python">
b = Builder("build_it &lt; $SOURCE &gt; $TARGET", suffix="-file")

def gen_suffix(env, sources):
    return "." + env['PLATFORM'] + "-file"

b = Builder("build_it &lt; $SOURCE &gt; $TARGET", suffix=gen_suffix)
b = Builder(
    "build_it &lt; $SOURCE &gt; $TARGET",
    suffix={None: ".sfx1", "$SRC_SFX_A": gen_suffix},
)
</programlisting>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>ensure_suffix</parameter></term>
  <listitem>
<para>If set to a true value,
ensures that targets will end in
<parameter>suffix</parameter>.
Thus, the suffix will also be added to any target strings
that have a suffix that is not already <parameter>suffix</parameter>.
The default behavior (also indicated by a false value)
is to leave unchanged
any target string that looks like it already has a suffix.</para>

<programlisting language="python">
b1 = Builder("build_it &lt; $SOURCE &gt; $TARGET", suffix=".out")
b2 = Builder(
    "build_it &lt; $SOURCE &gt; $TARGET", suffix=".out", ensure_suffix=True
)
env = Environment()
env['BUILDERS']['B1'] = b1
env['BUILDERS']['B2'] = b2

# Builds "foo.txt" because ensure_suffix is not set.
env.B1('foo.txt', 'foo.in')

# Builds "bar.txt.out" because ensure_suffix is set.
env.B2('bar.txt', 'bar.in')
</programlisting>

  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>src_suffix</parameter></term>
  <listitem>
<para>The expected source file name suffix.
<parameter>src_suffix</parameter>
may be a string or a list of strings.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="target_scanner">
  <term><parameter>target_scanner</parameter></term>
  <listitem>
<para>A Scanner object that
will be invoked to find
implicit dependencies for this target file.
Use only to specify Scanner objects that find
implicit dependencies
based on the target file
and &consenv;,
<emphasis>not</emphasis>
for implicit dependencies based on source files
(use <xref linkend="source_scanner"/> for those).
See <xref linkend="scanner_objects"/>
for information about creating your own Scanner objects.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="source_scanner">
  <term><parameter>source_scanner</parameter></term>
  <listitem>
<para>A Scanner object that
will be invoked to
find implicit dependencies in
any source files
used to build this target file.
Use to specify a scanner to
find things like
<literal>#include</literal>
lines in source files.
The pre-built
<classname>DirScanner</classname>
Scanner object may be used to
indicate that this Builder
should scan directory trees
for on-disk changes to files
that
&scons;
does not know about from other Builder or function calls.
See <xref linkend="scanner_objects"/>
for information about creating your own Scanner objects.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>target_factory</parameter></term>
  <listitem>
<para>A factory function that the Builder will use
to turn any targets specified as strings into SCons Nodes.
By default,
SCons assumes that all targets are files
(that is, the default factory is &File;).
Other useful <parameter>target_factory</parameter>
values include &Dir;
for when a Builder creates a directory target,
and &Entry;
for when a Builder can create either a file
or directory target.</para>

<para>Example:</para>

<programlisting language="python">
def my_mkdir(target, source, env):
    # target[0] will be a Dir node for 'new_directory'

MakeDirectoryBuilder = Builder(action=my_mkdir, target_factory=Dir)
env = Environment()
env.Append(BUILDERS={'MakeDirectory': MakeDirectoryBuilder})
env.MakeDirectory('new_directory', [])
</programlisting>

<para>Note that the call to the <function>MakeDirectory</function> Builder
needs to specify an empty source list
to make the filename string represent the builder's target.
&SCons; assumes a single positional argument to a builder
is the source, and would try to deduce the target name from it,
which, in the absence of an automatically-added prefix or suffix,
would lead to a matching target and source name
and a circular dependency.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>source_factory</parameter></term>
  <listitem>
<para>A factory function that the Builder will use
to turn any sources specified as strings into SCons Nodes.
By default,
SCons assumes that all source are files
(that is, the default factory is &File;).
Other useful <parameter>source_factory</parameter>
values include &Dir;
for when a Builder uses a directory as a source,
and &Entry;
for when a Builder can use files
or directories (or both) as sources.</para>

<para>Example:</para>

<programlisting language="python">
def collect(target, source, env):
    # target[0] will default to a File node for 'archive' (no target_factory)
    # source[0] will be a Dir node for 'directory_name'

CollectBuilder = Builder(action=collect, source_factory=Dir)
env = Environment()
env.Append(BUILDERS={'Collect': CollectBuilder})
env.Collect('archive', 'directory_name')
</programlisting>
  </listitem>
  </varlistentry>

  <varlistentry id="emitter_function">
  <term><parameter>emitter</parameter></term>
  <listitem>
<para>A function or list of functions to manipulate the target and source
lists before dependencies are established
and the target(s) are actually built.
<parameter>emitter</parameter>
can also be a string containing a &consvar; to expand
to an emitter function or list of functions,
or a dictionary mapping source file suffixes
to emitter functions.
(Only the suffix of the first source file
is used to select the actual emitter function
from an emitter dictionary.)</para>

<para>A function passed as <parameter>emitter</parameter>
must accept three arguments:
<parameter>source</parameter>,
<parameter>target</parameter> and
<parameter>env</parameter>.
<parameter>source</parameter> is a list of source nodes,
<parameter>target</parameter> is a list of target nodes,
<parameter>env</parameter> is the &consenv; to use for context.
</para>

<para>An emitter must return a tuple containing two lists,
the list of targets to be built by this builder,
and the list of sources for this builder.</para>

<para>Example:</para>

<programlisting language="python">
def e(target, source, env):
    return target + ['foo.foo'], source + ['foo.src']

# Simple association of an emitter function with a Builder.
b = Builder("my_build &lt; $TARGET &gt; $SOURCE", emitter=e)

def e2(target, source, env):
    return target + ['bar.foo'], source + ['bar.src']

# Simple association of a list of emitter functions with a Builder.
b = Builder("my_build &lt; $TARGET &gt; $SOURCE", emitter=[e, e2])

# Calling an emitter function through a construction variable.
env = Environment(MY_EMITTER=e)
b = Builder("my_build &lt; $TARGET &gt; $SOURCE", emitter='$MY_EMITTER')

# Calling a list of emitter functions through a construction variable.
env = Environment(EMITTER_LIST=[e, e2])
b = Builder("my_build &lt; $TARGET &gt; $SOURCE", emitter='$EMITTER_LIST')

# Associating multiple emitters with different file
# suffixes using a dictionary.
def e_suf1(target, source, env):
    return target + ['another_target_file'], source

def e_suf2(target, source, env):
    return target, source + ['another_source_file']

b = Builder(
    action="my_build &lt; $TARGET &gt; $SOURCE",
    emitter={'.suf1': e_suf1, '.suf2': e_suf2}
)
</programlisting>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>multi</parameter></term>
  <listitem>
<para>Specifies whether this builder is allowed to be called multiple times for
the same target file(s). The default is <constant>False</constant>,
which means the builder
can not be called multiple times for the same target file(s). Calling a
builder multiple times for the same target simply adds additional source
files to the target; it is not allowed to change the environment associated
with the target, specify additional environment overrides,
or associate a different
builder with the target.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>env</parameter></term>
  <listitem>
<para>A &consenv; that can be used
to fetch source code using this Builder.
(Note that this environment is
<emphasis>not</emphasis>
used for normal builds of normal target files,
which use the environment that was
used to call the Builder for the target file.)</para>
  </listitem>
  </varlistentry>

  <varlistentry id="generator_function">
  <term><parameter>generator</parameter></term>
  <listitem>
<para>A function that returns a list of actions that will be executed to build
the target(s) from the source(s).
The returned action(s) may be
an Action object, or anything that
can be converted into an Action object
(see the next section).</para>

<para>A function passed as <parameter>generator</parameter>
must accept four arguments:
<parameter>source</parameter>,
<parameter>target</parameter>,
<parameter>env</parameter> and
<parameter>for_signature</parameter>.
<parameter>source</parameter> is a list of source nodes,
<parameter>target</parameter> is a list of target nodes,
<parameter>env</parameter> is the &consenv; to use for context,
and <parameter>for_signature</parameter> is
a Boolean value that tells the function
if it is being called for the purpose of generating a &buildsig;
(as opposed to actually executing the command).
Since the &buildsig; is used for rebuild determination,
the function should omit those elements
that do not affect whether a rebuild should be triggered
if <parameter>for_signature</parameter> is true.
</para>

<para>Example:</para>

<programlisting language="python">
def g(source, target, env, for_signature):
    return [["gcc", "-c", "-o"] + target + source]

b = Builder(generator=g)
</programlisting>


<para>The
<emphasis>generator</emphasis>
and
<emphasis>action</emphasis>
arguments must not both be used for the same Builder.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>src_builder</parameter></term>
  <listitem>
<para>Specifies a builder to use when a source file name suffix does not match
any of the suffixes of the builder. Using this argument produces a
multi-stage builder.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>single_source</parameter></term>
  <listitem>
<para>Specifies that this builder expects exactly one source file per call. Giving
more than one source file without target files results in implicitly calling
the builder multiple times (once for each source given). Giving multiple
source files together with target files results in a
<exceptionname>UserError</exceptionname> exception.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>source_ext_match</parameter></term>
  <listitem>
<para>When the specified
<parameter>action</parameter>
argument is a dictionary,
the default behavior when a builder is passed
multiple source files is to make sure that the
extensions of all the source files match.
If it is legal for this builder to be
called with a list of source files with different extensions,
this check can be suppressed by setting
<parameter>source_ext_match</parameter>
to
<constant>False</constant>
or some other non-true value.
In this case, &scons;
will use the suffix of the first specified
source file to select the appropriate action from the
<parameter>action</parameter>
dictionary.</para>

<para>In the following example,
the setting of
<parameter>source_ext_match</parameter>
prevents
&scons;
from exiting with an error
due to the mismatched suffixes of
<filename>foo.in</filename>
and
<filename>foo.extra</filename>.</para>

<programlisting language="python">
b = Builder(action={'.in': 'build $SOURCES &gt; $TARGET'}, source_ext_match=False)
env = Environment(BUILDERS={'MyBuild': b})
env.MyBuild('foo.out', ['foo.in', 'foo.extra'])
</programlisting>

  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>env</parameter></term>
  <listitem>
<para>A &consenv; that can be used
to fetch source code using this Builder.
(Note that this environment is
<emphasis>not</emphasis>
used for normal builds of normal target files,
which use the environment that was
used to call the Builder for the target file.)</para>

<programlisting language="python">
b = Builder(action="build &lt; $SOURCE &gt; $TARGET")
env = Environment(BUILDERS={'MyBuild' : b})
env.MyBuild('foo.out', 'foo.in', my_arg='xyzzy')
</programlisting>

  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>chdir</parameter></term>
  <listitem>
<para>A directory from which scons
will execute the
action(s) specified
for this Builder.
If the
<parameter>chdir</parameter>
argument is
a string or a directory Node,
scons will change to the specified directory.
If the
<parameter>chdir</parameter>
is not a string or Node
and is non-zero,
then scons will change to the
target file's directory.</para>

<para>Note that scons will
<emphasis>not</emphasis>
automatically modify
its expansion of
&consvars; like
<envar>$TARGET</envar>
and
<envar>$SOURCE</envar>
when using the <parameter>chdir</parameter>
keyword argument--that is,
the expanded file names
will still be relative to the project top directory,
and consequently incorrect
relative to the chdir directory.
Builders created using <parameter>chdir</parameter> keyword argument,
will need to use &consvar;
expansions like
<literal>${TARGET.file}</literal>
and
<literal>${SOURCE.file}</literal>
to use just the filename portion of the
targets and source.</para>

<programlisting language="python">
b = Builder(action="build &lt; ${SOURCE.file} &gt; ${TARGET.file}", chdir=True)
env = Environment(BUILDERS={'MyBuild' : b})
env.MyBuild('sub/dir/foo.out', 'sub/dir/foo.in')
</programlisting>

<warning>
<para>
&Python; only tracks one current directory location,
even if there are multiple executing threads.
This means that use of the
<parameter>chdir</parameter>
argument will
<emphasis>not</emphasis>
work with &SCons; in multi-threaded mode
(the <link linkend="opt-jobs"><option>-j</option></link> option),
because individual worker threads spawned
by SCons interfere with each other
when they start changing directory.</para>
</warning>
  </listitem>
  </varlistentry>
</variablelist>

<para>Any additional keyword arguments supplied
when a Builder object is created
(that is, when the &f-link-Builder; function is called)
will be set in the executing &consenv;
when the Builder object is called.
The canonical example here would be
to set a &consvar; to
the repository of a source code system.</para>

<para>Any such keyword arguments supplied
when a Builder object is called
will only be associated with the target
created by that particular &f-Builder; call
(and any other files built as a
result of the call).
These extra keyword arguments are passed to the
following functions:
<link linkend='generator_function'>command generator functions</link>,
<link linkend='miscellaneous_action_functions'>function Actions</link>,
and
<link linkend='emitter_function'>emitter functions</link>.
</para>

<para>
When debugging errors in a custom builder method,
remember that the builder's Action is executed asynchronously -
the builder call in the &SConscript; only instructs
&SCons; what you want built, while the actual building is
scheduled later (if necessary) by the taskmaster.
As a result, wrapping a builder call in a
<systemitem>try</systemitem> block is not useful,
as success in the builder call is not the same as
the build itself succeeding.
If necessary, code a builder's Action to exit with
a useful error message indicating the problem in the &SConscript; file.
Attempting programmatic recovery from build errors is rarely useful.
</para>

</refsect2>

<refsect2 id='action_objects'>
<title>Action Objects</title>

<para>The
&f-link-Builder;
factory function will turn its
<parameter>action</parameter>
keyword argument into an appropriate
internal Action object, as will
the &f-link-Command; function.
You can also explicitly create Action objects
for passing to &f-Builder;, or other functions
that take actions as arguments,
by calling the &f-link-Action; factory function.
This may more efficient when multiple
Builder objects need to do the same thing
rather than letting each of those Builder objects
create a separate Action object.
It also allows more flexible configuration
of an Action object. For example, to control
the message printed when the action is taken
you need to create the action object using &f-Action;.
</para>

<para>The
&Action; factory function
returns an appropriate object for the action
represented by the type of the
<parameter>action</parameter> argument
(the first positional parameter):</para>

<itemizedlist>
  <listitem>
<para>If <parameter>action</parameter> is already an Action object,
the object is simply returned.</para>
  </listitem>

  <listitem>
<para>If <parameter>action</parameter> is a string,
a command-line Action is returned.
If such a string begins with <literal>@</literal>,
the command line is not printed.
If the string begins with hyphen
(<literal>-</literal>),
the exit status from the specified command
is ignored, allowing execution to continue
even if the command reports failure:</para>

<programlisting language="python">
Action('$CC -c -o $TARGET $SOURCES')

# Doesn't print the line being executed.
Action('@build $TARGET $SOURCES')

# Ignores return value
Action('-build $TARGET $SOURCES')
</programlisting>
  </listitem>

  <listitem>
<para>If <parameter>action</parameter> is a list,
then a list of Action objects is returned.
An Action object is created as necessary
for each element in the list.
If an element within
the list is itself a list,
the embedded list is taken as the
command and arguments to be executed via
the command line.
This allows white space to be enclosed
in an argument rather than taken as a separator by defining
a command in a list within a list:</para>

<programlisting language="python">
Action([['cc', '-c', '-DWHITE SPACE', '-o', '$TARGET', '$SOURCES']])
</programlisting>
  </listitem>

  <listitem>
<para>If <parameter>action</parameter> is a callable object,
a Function Action is returned.
The callable must accept three keyword arguments:
<parameter>target</parameter>,
<parameter>source</parameter> and
<parameter>env</parameter>.
<parameter>target</parameter>
is a Node object representing the target file,
<parameter>source</parameter>
is a Node object representing the source file and
<parameter>env</parameter>
is the &consenv; used for building the target file.
</para>

<para>
The
<parameter>target</parameter>
and
<parameter>source</parameter>
arguments may be lists of Node objects if there is
more than one target file or source file.
The actual target and source file name(s) may
be retrieved from their Node objects
via the built-in &Python; <function>str</function> function:</para>

<programlisting language="python">
target_file_name = str(target)
source_file_names = [str(x) for x in source]
</programlisting>

<para>The function should return
<literal>0</literal>
or
<constant>None</constant>
to indicate a successful build of the target file(s).
The function may raise an exception
or return a non-zero exit status
to indicate an unsuccessful build.</para>

<programlisting language="python">
def build_it(target=None, source=None, env=None):
    # build the target from the source
    return 0

a = Action(build_it)
</programlisting>
  </listitem>

  <listitem>
<para>If
<parameter>action</parameter>
is not one of the above types,
no action object is generated and &f-Action;
returns <constant>None</constant>.</para>
  </listitem>
</itemizedlist>

<para>The environment method form &f-link-env-Action;
will expand &consvars; in any argument strings,
including
<parameter>action</parameter>,
at the time it is called,
using the &consvars; in the &consenv; through which
it was called. The global function form &f-link-Action;
delays variable expansion until
the Action object is actually used.
</para>

<para>The optional second argument to &f-Action;
is used to control the output
which is printed when the Action is actually performed.
If this parameter is omitted,
or if the value is an empty string,
a default output depending on the type of the action is used.
For example, a command-line action will print the executed command.
The following argument types are accepted:
</para>

<itemizedlist>
  <listitem>
<para>If the second argument is a string,
or if the <parameter>cmdstr</parameter> keyword argument is supplied,
the string defines what is printed.
Substitution is performed on the string before it is printed.
The string typically contains substitutable variables, notably
<literal>$TARGET(S)</literal> and <literal>$SOURCE(S)</literal>,
or consists of just a single variable
which is optionally defined somewhere else.
&SCons; itself heavily uses the latter variant.</para>
  </listitem>

  <listitem>
<para>If the second argument is a function,
or if the <parameter>strfunction</parameter> keyword argument is supplied,
the function will be called to obtain the string
to be printed when the action is performed.
The function
must accept three keyword arguments:
<parameter>target</parameter>,
<parameter>source</parameter> and
<parameter>env</parameter>,
with the same interpretation as for a callable
<parameter>action</parameter> argument above.
The function is responsible for handling any required substitutions.
</para>
  </listitem>

  <listitem>
<para>If the second argument is <constant>None</constant>,
or if <literal>cmdstr=None</literal> is supplied,
output is suppressed entirely.</para>
  </listitem>
</itemizedlist>

<para>
The <parameter>cmdstr</parameter> and
<parameter>strfunction</parameter>
keyword arguments may not both be supplied in a single call to &f-Action;
</para>

<para>
Printing of action strings is affected by the setting of
&cv-link-PRINT_CMD_LINE_FUNC;.
</para>

<para>Examples:</para>

<programlisting language="python">
def build_it(target, source, env):
    # build the target from the source
    return 0

def string_it(target, source, env):
    return "building '%s' from '%s'" % (target[0], source[0])

# Use a positional argument.
f = Action(build_it, string_it)
s = Action(build_it, "building '$TARGET' from '$SOURCE'")

# Alternatively, use a keyword argument.
f = Action(build_it, strfunction=string_it)
s = Action(build_it, cmdstr="building '$TARGET' from '$SOURCE'")

# You can provide a configurable variable.
l = Action(build_it, '$STRINGIT')
</programlisting>

<para>Any additional positional arguments, if present,
may either be &consvars; or lists of &consvars;
whose values will be included in the signature of the Action
(the &buildsig;)
when deciding whether a target should be rebuilt because the action changed.
Such variables may also be specified using the
<parameter>varlist</parameter>
keyword parameter;
both positional and keyword forms may be present, and will be combined.
This is necessary whenever you want a target to be rebuilt
when a specific &consvar; changes.
This is not often needed for a string action,
as the expanded variables will normally be part of the command line,
but may be needed if a &Python; function action uses
the value of a &consvar; when generating the command line.</para>

<programlisting language="python">
def build_it(target, source, env):
    # build the target from the 'XXX' construction variable
    with open(target[0], 'w') as f:
        f.write(env['XXX'])
    return 0

# Use positional arguments.
a = Action(build_it, '$STRINGIT', ['XXX'])

# Alternatively, use a keyword argument.
a = Action(build_it, varlist=['XXX'])
</programlisting>

<para>The
&Action;
factory function
can be passed the following
optional keyword arguments
to modify the Action object's behavior:</para>

<variablelist>
  <varlistentry>
  <term><parameter>chdir</parameter></term>
  <listitem>
<para>
If <parameter>chdir</parameter> is true
(the default is <constant>False</constant>),
&SCons; will change directories before
executing the action.
If the value of <parameter>chdir</parameter>
is a string or a directory Node,
&SCons; will change to the specified directory.
Otherwise, if <parameter>chdir</parameter> evaluates true,
&SCons; will change to the
target file's directory.</para>

<para>Note that &SCons; will
<emphasis>not</emphasis>
automatically modify
its expansion of
&consvars; like
&cv-TARGET; and &cv-SOURCE;
when using the <parameter>chdir</parameter>
parameter - that is,
the expanded file names
will still be relative to
the project top directory,
and consequently incorrect
relative to the chdir directory.
Builders created using <parameter>chdir</parameter> keyword argument,
will need to use &consvar;
expansions like
<literal>${TARGET.file}</literal>
and
<literal>${SOURCE.file}</literal>
to use just the filename portion of the
targets and source. Example:</para>

<programlisting language="python">
a = Action("build &lt; ${SOURCE.file} &gt; ${TARGET.file}", chdir=True)
</programlisting>
  </listitem>
  </varlistentry>
  <varlistentry>
  <term><parameter>exitstatfunc</parameter></term>
  <listitem>
<para>
If provided, must be a callable which accepts a single parameter,
the exit status (or return value)
from the specified action,
and which returns an arbitrary
or modified value.
This can be used, for example,
to specify that an Action object's
return value should be ignored
under special conditions
and SCons should, therefore,
consider that the action always succeeds. Example:</para>

<programlisting language="python">
def always_succeed(s):
    # Always return 0, which indicates success.
    return 0

a = Action("build &lt; ${SOURCE.file} &gt; ${TARGET.file}", exitstatfunc=always_succeed)
</programlisting>
  </listitem>
  </varlistentry>
  <varlistentry>
  <term><parameter>batch_key</parameter></term>
  <listitem>
<para>
If provided, indicates that the Action can create multiple target files
by processing multiple independent source files simultaneously.
(The canonical example is "batch compilation"
of multiple object files
by passing multiple source files
to a single invocation of a compiler
such as &MSVC;.
If the
<parameter>batch_key</parameter>
argument evaluates True and is not a callable object,
the configured Action object will cause
&scons;
to collect all targets built with the Action object
and configured with the same &consenv;
into single invocations of the Action object's
command line or function.
Command lines will typically want to use the
&cv-CHANGED_SOURCES; &consvar;
(and possibly &cv-CHANGED_TARGETS; as well)
to only pass to the command line those sources that
have actually changed since their targets were built.
Example:</para>

<programlisting language="python">
a = Action('build $CHANGED_SOURCES', batch_key=True)
</programlisting>

<para>The
<parameter>batch_key</parameter>
argument may also be
a callable function
that returns a key that
will be used to identify different
"batches" of target files to be collected
for batch building.
A
<parameter>batch_key</parameter>
function must accept four parameters:
<parameter>action</parameter>,
<parameter>env</parameter>,
<parameter>target</parameter> and
<parameter>source</parameter>.
The first parameter, <parameter>action</parameter>,
is the active action object.
The second parameter, <parameter>env</parameter>,
is the &consenv; configured for the target.
The <parameter>target</parameter> and <parameter>source</parameter>
parameters are the lists of targets and sources
for the configured action.
</para>

<para>The returned key should typically
be a tuple of values derived from the arguments,
using any appropriate logic to decide
how multiple invocations should be batched.
For example, a
<parameter>batch_key</parameter>
function may decide to return
the value of a specific &consvar;
from <parameter>env</parameter>
which will cause
&scons;
to batch-build targets
with matching values of that &consvar;,
or perhaps return the
&Python; <function>id</function>()
of the entire &consenv;,
in which case
&scons;
will batch-build
all targets configured with the same &consenv;.
Returning
<constant>None</constant>
indicates that
the particular target should
<emphasis>not</emphasis>
be part of any batched build,
but instead will be built
by a separate invocation of action's
command or function.
Example:</para>

<programlisting language="python">
def batch_key(action, env, target, source):
    tdir = target[0].dir
    if tdir.name == 'special':
        # Don't batch-build any target
        # in the special/ subdirectory.
        return None
    return (id(action), id(env), tdir)
a = Action('build $CHANGED_SOURCES', batch_key=batch_key)
</programlisting>
  </listitem>
  </varlistentry>
</variablelist>

<refsect3 id='miscellaneous_action_functions'>
<title>Miscellaneous Action Functions</title>

<para>&SCons;
supplies Action functions
that arrange for various common
file and directory manipulations
to be performed.
These are similar in concept to "tasks" in the
&Ant; build tool,
although the implementation is slightly different.
These functions do not actually
perform the specified action
at the time the function is called,
but rather are factory functions which
return an Action object
that can be executed at the
appropriate time.</para>

<para>
There are two natural ways
that these
Action Functions
are intended to be used.</para>

<para>First,
if you need
to perform the action
at the time the &SConscript;
file is being read,
you can use the
&f-link-Execute;
global function:</para>

<programlisting language="python">
Execute(Touch('file'))
</programlisting>

<para>Second,
you can use these functions
to supply Actions in a list
for use by the &f-link-env-Command; method.
This can allow you to
perform more complicated
sequences of file manipulation
without relying
on platform-specific
external commands:
</para>

<programlisting language="python">
env = Environment(TMPBUILD='/tmp/builddir')
env.Command(
    target='foo.out',
    source='foo.in',
    action=[
        Mkdir('$TMPBUILD'),
        Copy('$TMPBUILD', '${SOURCE.dir}'),
        "cd $TMPBUILD &amp;&amp; make",
        Delete('$TMPBUILD'),
    ],
)
</programlisting>

<variablelist>
  <varlistentry>
  <term><function>Chmod</function>(<parameter>dest, mode</parameter>)</term>
  <listitem>
<para>Returns an Action object that
changes the permissions on the specified
<parameter>dest</parameter>
file or directory to the specified
<parameter>mode</parameter>
which can be octal or string, similar to the POSIX
<command>chmod</command> command.
Examples:</para>

<programlisting language="python">
Execute(Chmod('file', 0o755))

env.Command(
    'foo.out',
    'foo.in',
    [Copy('$TARGET', '$SOURCE'), Chmod('$TARGET', 0o755)],
)

Execute(Chmod('file', "ugo+w"))

env.Command(
    'foo.out',
    'foo.in',
    [Copy('$TARGET', '$SOURCE'), Chmod('$TARGET', "ugo+w")],
)
</programlisting>

<para>
The behavior of <function>Chmod</function> is limited on Windows
and on WebAssembly platforms,
see the notes in the &Python; documentation for
<ulink url="https://docs.python.org/3/library/os.html#os.chmod">
os.chmod</ulink>, which is the underlying function.
</para>

  </listitem>
  </varlistentry>

  <varlistentry>
  <term><function>Copy</function>(<parameter>dest, src</parameter>)</term>
  <listitem>
<para>Returns an Action object
that will copy the
<parameter>src</parameter>
source file or directory to the
<parameter>dest</parameter>
destination file or directory.
If <parameter>src</parameter> is a list,
<parameter>dest</parameter> must be a directory
if it already exists.
Examples:</para>

<programlisting language="python">
Execute(Copy('foo.output', 'foo.input'))

env.Command('bar.out', 'bar.in', Copy('$TARGET', '$SOURCE'))
</programlisting>

  </listitem>
  </varlistentry>

  <varlistentry>
  <term><function>Delete</function>(<parameter>entry, [must_exist]</parameter>)</term>
  <listitem>
<para>Returns an Action that
deletes the specified
<parameter>entry</parameter>,
which may be a file or a directory tree.
If a directory is specified,
the entire directory tree
will be removed.
If the
<parameter>must_exist</parameter>
flag is set to a true value,
then a &Python; error will be raised
if the specified entry does not exist;
the default is false,
that is, the Action will silently do nothing
if the entry does not exist.
Examples:</para>

<programlisting language="python">
Execute(Delete('/tmp/buildroot'))

env.Command(
    'foo.out',
    'foo.in',
    action=[
        Delete('${TARGET.dir}'),
        MyBuildAction,
    ],
)

Execute(Delete('file_that_must_exist', must_exist=True))
</programlisting>

  </listitem>
  </varlistentry>

  <varlistentry>
  <term><function>Mkdir</function>(<parameter>name</parameter>)</term>
  <listitem>
<para>Returns an Action
that creates the directory
<parameter>name</parameter>
and all needed intermediate directories.
<parameter>name</parameter> may also be a list
of directories to create.
Examples:</para>

<programlisting language="python">
Execute(Mkdir('/tmp/outputdir'))

env.Command(
    'foo.out',
    'foo.in',
    action=[
        Mkdir('/tmp/builddir'),
        Copy('/tmp/builddir/foo.in', '$SOURCE'),
        "cd /tmp/builddir &amp;&amp; make",
        Copy('$TARGET', '/tmp/builddir/foo.out'),
    ],
)
</programlisting>

  </listitem>
  </varlistentry>

  <varlistentry>
  <term><function>Move</function>(<parameter>dest, src</parameter>)</term>
  <listitem>
<para>Returns an Action
that moves the specified
<parameter>src</parameter>
file or directory to
the specified
<parameter>dest</parameter>
file or directory.
Examples:</para>

<programlisting language="python">
Execute(Move('file.destination', 'file.source'))

env.Command(
    'output_file',
    'input_file',
    action=[MyBuildAction, Move('$TARGET', 'file_created_by_MyBuildAction')],
)
</programlisting>

  </listitem>
  </varlistentry>

  <varlistentry>
  <term><function>Touch</function>(<parameter>file</parameter>)</term>
  <listitem>
<para>Returns an Action
that updates the modification time
on the specified
<parameter>file</parameter>.
Examples:</para>

<programlisting language="python">
Execute(Touch('file_to_be_touched'))

env.Command('marker', 'input_file', action=[MyBuildAction, Touch('$TARGET')])
</programlisting>

  </listitem>
  </varlistentry>
</variablelist>
</refsect3>

<refsect3 id='variable_substitution'>
<title>Variable Substitution</title>

<para>
Before executing a command, &scons;
performs parameter expansion (<firstterm>substitution</firstterm>)
on the string that makes up the action part of the builder.
The format of a substitutable parameter is
<literal>${<replaceable>expression</replaceable>}</literal>.
If <replaceable>expression</replaceable> refers to a variable,
the braces in <literal>${<replaceable>expression</replaceable>}</literal>
can be omitted <emphasis>unless</emphasis> the variable name is
immediately followed by a character that could either be interpreted
as part of the name, or is &Python; syntax such as
<emphasis role="bold">[</emphasis> (for indexing/slicing)
or <emphasis role="bold">.</emphasis> (for attribute access -
see <link linkend="special_attributes">Special Attributes</link> below).
</para>

<para>
If <replaceable>expression</replaceable> refers to a &consvar;,
it (including the <literal>$</literal> or <literal>${ }</literal>)
is replaced with the value of that variable in the
&consenv; at the time of execution.
If <replaceable>expression</replaceable> looks like
a variable name but is not defined in the &consenv;
it is replaced with an empty string.
If <replaceable>expression</replaceable> refers to one of the
<link linkend="special_variables">Special Variables</link>
(see below) the corresponding value of the variable is substituted.
<replaceable>expression</replaceable> may also be
a &Python; expression to be evaluated.
See <link linkend='python_code_substitution'>Python Code Substitution</link>
below for a description.
</para>

<para>&SCons; uses the following rules when converting &consvars; into
command line strings:</para>

<itemizedlist>
  <listitem>
  <para>If the value is a string it is interpreted as space delimited
  command line arguments.</para>
  </listitem>

  <listitem>
  <para>If the value is a list it is interpreted as a list of command
  line arguments. Each element of the list is converted to a string.</para>
  </listitem>

  <listitem>
  <para>Anything that is not a list or string is converted to a string and
  interpreted as a single command line argument.</para>
  </listitem>

  <listitem>
  <para>Newline characters (<literal>\n</literal>) delimit lines.
  The newline parsing is done after
  all other parsing, so it is not possible for arguments (e.g. file names) to
  contain embedded newline characters.</para>
  </listitem>

  <listitem>
  <para>For a literal <emphasis role="bold">$</emphasis>
  use <emphasis role="bold">$$</emphasis>.
  For example, <literal>$$FOO</literal> will be left in the
  final string as <literal>$FOO</literal>.</para>
  </listitem>
</itemizedlist>

<para>
When a build action is executed, a hash of the command line is
saved, together with other information about the target(s) built
by the action, for future use in rebuild determination.
This is called the <firstterm>&buildsig;</firstterm>
(or <firstterm>&build_action; signature</firstterm>).
The escape sequence
<emphasis role="bold">$(</emphasis>
<replaceable>subexpression</replaceable>
<emphasis role="bold">$)</emphasis>
may be used to indicate parts of a command line
that may change without
causing a rebuild--that is,
which are not to be included when calculating the &buildsig;.
All text from
<emphasis role="bold">$(</emphasis>
up to and including the matching
<emphasis role="bold">$)</emphasis>
will be removed from the command line
before it is added to the &buildsig;
while only the
<emphasis role="bold">$(</emphasis>
and
<emphasis role="bold">$)</emphasis>
will be removed before the command is executed.
For example, the command line string:</para>

<programlisting language="python">
"echo Last build occurred $( $TODAY $). &gt; $TARGET"
</programlisting>

<para>would execute the command:</para>

<screen>
echo Last build occurred $TODAY. &gt; $TARGET
</screen>

<para>but the &buildsig; added to any target files would be computed from:</para>

<screen>
echo Last build occurred  . &gt; $TARGET
</screen>

<para>While &consvars; are normally directly substituted,
if a &consvar; has a value which
is a callable &Python; object
(a function, or a class with a <literal>__call__</literal> method),
that object is called during substitution.
The callable must accept four arguments:
<parameter>target</parameter>,
<parameter>source</parameter>,
<parameter>env</parameter> and
<parameter>for_signature</parameter>.
<parameter>source</parameter> is a list of source nodes,
<parameter>target</parameter> is a list of target nodes,
<parameter>env</parameter> is the &consenv; to use for context,
and <parameter>for_signature</parameter> is
a boolean value that tells the callable
if it is being called for the purpose of generating a &buildsig;.
Since the &buildsig; is used for rebuild determination,
variable elements that do not affect whether
a rebuild should be triggered
should be omitted from the returned string
if <parameter>for_signature</parameter> is true.
See <emphasis role="bold">$(</emphasis>
and <emphasis role="bold">$)</emphasis> above
for the syntax.
</para>

<para>
&SCons; will insert whatever
the callable returns
into the expanded string:
</para>

<programlisting language="python">
def foo(target, source, env, for_signature):
    return "bar"

# Will expand $BAR to "bar baz"
env = Environment(FOO=foo, BAR="$FOO baz")
</programlisting>

<para>As a reminder, substitution happens when
<literal>$BAR</literal> is actually used in a
builder action.  The value of <literal>env['BAR']</literal>
will be exactly as it was set: <literal>"$FOO baz"</literal>.
This can make debugging tricky,
as the substituted result is not available at the time
the &SConscript; files are being interpreted and
thus not available to the <systemitem>print</systemitem> function.
However, you can perform the substitution on demand
by calling the &f-link-env-subst; method for this purpose.
</para>

<para>You can use this feature to pass arguments to a
callable variable by creating a callable class
that stores passed arguments in the instance,
and then uses them
(in the <methodname>__call__</methodname> method)
when the instance is called.
Note that in this case,
the entire variable expansion must
be enclosed by curly braces
so that the arguments will
be associated with the
instantiation of the class:</para>

<programlisting language="python">
class foo:
    def __init__(self, arg):
        self.arg = arg

    def __call__(self, target, source, env, for_signature):
        return self.arg + " bar"

# Will expand $BAR to "my argument bar baz"
env=Environment(FOO=foo, BAR="${FOO('my argument')} baz")
</programlisting>

</refsect3>

<refsect3 id='special_variables'>
<title>Substitution: Special Variables</title>

<para>
Besides regular &consvars;, scons provides the following
<firstterm>Special Variables</firstterm> for use in expanding commands:</para>

<variablelist>
  <varlistentry>
  <term>&cv-CHANGED_SOURCES;</term>
  <listitem>
<para>The file names of all sources of the build command
that have changed since the target was last built.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term>&cv-CHANGED_TARGETS;</term>
  <listitem>
<para>The file names of all targets that would be built
from sources that have changed since the target was last built.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term>&cv-SOURCE;</term>
  <listitem>
<para>The file name of the source of the build command,
or the file name of the first source
if multiple sources are being built.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term>&cv-SOURCES;</term>
  <listitem>
<para>The file names of the sources of the build command.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term>&cv-TARGET;</term>
  <listitem>
<para>The file name of the target being built,
or the file name of the first target
if multiple targets are being built.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term>&cv-TARGETS;</term>
  <listitem>
<para>The file names of all targets being built.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term>&cv-UNCHANGED_SOURCES;</term>
  <listitem>
<para>The file names of all sources of the build command
that have
<emphasis>not</emphasis>
changed since the target was last built.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term>&cv-UNCHANGED_TARGETS;</term>
  <listitem>
<para>The file names of all targets that would be built
from sources that have
<emphasis>not</emphasis>
changed since the target was last built.</para>
  </listitem>
  </varlistentry>
</variablelist>

<para>
These names are reserved
and may not be assigned to or used as &consvars;.
&SCons; computes them in a context-dependent manner
and they are not retrieved from a &consenv;.
</para>

<para>For example, the following builder call:
</para>

<programlisting language="python">
env = Environment(CC='cc')
env.Command(
    target=['foo'],
    source=['foo.c', 'bar.c'],
    action='@echo $CC -c -o $TARGET $SOURCES'
)
</programlisting>

<para>would produce the following output:</para>

<screen>
cc -c -o foo foo.c bar.c
</screen>

<para>
In the previous example, a string
<code>${SOURCES[1]}</code>
would expand to: <computeroutput>bar.c</computeroutput>.
</para>

</refsect3>

<refsect3 id='special_attributes'>
<title>Substitution: Special Attributes
</title>
<para>A variable name may
have the following
modifiers appended within the enclosing curly braces
to access properties of the interpolated string.
These are known as <firstterm>special attributes</firstterm>.
</para>

<simplelist>
  <member><parameter>base</parameter> -
    The base path of the file name,
    including the directory path
    but excluding any suffix.
  </member>
  <member><parameter>dir</parameter> - The name of the directory in which the file exists.</member>
  <member><parameter>file</parameter> -  The file name, minus any directory portion.</member>
  <member><parameter>filebase</parameter> - Like <parameter>file</parameter> but minus its suffix.</member>
  <member><parameter>suffix</parameter> - Just the file suffix.</member>
  <member><parameter>abspath</parameter> - The absolute path name of the file.</member>
  <member><parameter>relpath</parameter> - The path name of the file relative to the project top directory.</member>
  <member><parameter>posix</parameter> -
    The path with directories separated by forward slashes
    (<emphasis role="bold">/</emphasis>).
    Sometimes necessary on Windows systems
    when a path references a file on other (POSIX) systems.
  </member>
  <member><parameter>windows</parameter> -
    The path with directories separated by backslashes
    (<emphasis role="bold"><literal>\\</literal></emphasis>).
    Sometimes necessary on POSIX-style systems
    when a path references a file on other (Windows) systems.
    <parameter>win32</parameter> is a (deprecated) synonym for
    <parameter>windows</parameter>.
  </member>
  <member><parameter>srcpath</parameter> -
    The directory and file name to the source file linked to this file through
    &f-VariantDir;().
    If this file isn't linked,
    it just returns the directory and filename unchanged.
  </member>
  <member><parameter>srcdir</parameter> -
    The directory containing the source file linked to this file through
    &f-VariantDir;().
    If this file isn't linked,
    it just returns the directory part of the filename.
  </member>
  <member><parameter>rsrcpath</parameter> -
    The directory and file name to the source file linked to this file through
    &f-VariantDir;().
    If the file does not exist locally but exists in a Repository,
    the path in the Repository is returned.
    If this file isn't linked, it just returns the
    directory and filename unchanged.
  </member>
  <member><parameter>rsrcdir</parameter> -
    The Repository directory containing the source file linked to this file through
    &VariantDir;().
    If this file isn't linked,
    it just returns the directory part of the filename.
  </member>
</simplelist>

<para>For example, the specified target will
expand as follows for the corresponding modifiers:</para>

<literallayout class="monospaced">
$TARGET              =&gt; sub/dir/file.x
${TARGET.base}       =&gt; sub/dir/file
${TARGET.dir}        =&gt; sub/dir
${TARGET.file}       =&gt; file.x
${TARGET.filebase}   =&gt; file
${TARGET.suffix}     =&gt; .x
${TARGET.abspath}    =&gt; /top/dir/sub/dir/file.x
${TARGET.relpath}    =&gt; sub/dir/file.x

$TARGET              =&gt; ../dir2/file.x
${TARGET.abspath}    =&gt; /top/dir2/file.x
${TARGET.relpath}    =&gt; ../dir2/file.x

SConscript('src/SConscript', variant_dir='sub/dir')
$SOURCE              =&gt; sub/dir/file.x
${SOURCE.srcpath}    =&gt; src/file.x
${SOURCE.srcdir}     =&gt; src

Repository('/usr/repository')
$SOURCE              =&gt; sub/dir/file.x
${SOURCE.rsrcpath}   =&gt; /usr/repository/src/file.x
${SOURCE.rsrcdir}    =&gt; /usr/repository/src
</literallayout>

<para>
Some modifiers can be combined, like
<literal>${TARGET.srcpath.base)</literal>,
<literal>${TARGET.file.suffix}</literal>, etc.
</para>

</refsect3>

<refsect3 id='python_code_substitution'>
<title>Python Code Substitution</title>

<para>
If a substitutable expression using the notation
<literal>${<replaceable>expression</replaceable>}</literal>
does not appear to match one of the other substitution patterns,
it is evaluated as a &Python; expression.
This uses &Python;'s <function>eval</function> function,
with the <parameter>globals</parameter> parameter set to
the current environment's set of &consvars;,
and the result substituted in.
So in the following case:</para>

<programlisting language="python">
env.Command(
    'foo.out', 'foo.in', "echo ${COND==1 and 'FOO' or 'BAR'} &gt; $TARGET"
)
</programlisting>

<para>the command executed will be either</para>

<screen>
echo FOO &gt; foo.out
</screen>

<para>or</para>

<screen>
echo BAR &gt; foo.out
</screen>

<para>according to the current value of <literal>env['COND']</literal>
when the command is executed.
The evaluation takes place when the target is being
built, not when the &SConscript; is being read.  So if
<literal>env['COND']</literal> is changed
later in the &SConscript;, the final value will be used.</para>

<para>Here's a more complete example.  Note that all of
<envar>COND</envar>,
<envar>FOO</envar>,
and
<envar>BAR</envar> are &consvars;,
and their values are substituted into the final command.
<envar>FOO</envar> is a list, so its elements are interpolated
separated by spaces.</para>

<programlisting language="python">
env=Environment()
env['COND'] = 1
env['FOO'] = ['foo1', 'foo2']
env['BAR'] = 'barbar'
env.Command(
    'foo.out', 'foo.in', "echo ${COND==1 and FOO or BAR} &gt; $TARGET"
)
</programlisting>

<para>will execute:</para>
<screen>
echo foo1 foo2 &gt; foo.out
</screen>

<para>
In point of fact, &Python; expression evaluation is
how the special attributes are substituted:
they are simply attributes of the &Python; objects
that represent &cv-TARGET;, &cv-SOURCES;, etc.,
which &SCons; passes to <function>eval</function> which
returns the value.
</para>

<caution><para>
Use of the &Python; <function>eval</function> function
is considered to have security implications, since,
depending on input sources,
arbitrary unchecked strings of code can be executed by the &Python; interpreter.
Although &SCons; makes use of it in a somewhat restricted context,
you should be aware of this issue when using the
<literal>${python-expression-for-subst}</literal> form.
</para></caution>
</refsect3>
</refsect2>

<refsect2 id='scanner_objects'>
<title>Scanner Objects</title>

<para>
Scanner objects are used
to scan specific file types for implicit dependencies,
for example embedded preprocessor/compiler directives
that cause other files to be included during processing.
&SCons; has a number of pre-built Scanner objects,
so it is usually only necessary to set up Scanners for new file types.
You do this by calling the &f-link-Scanner; factory function.
&f-Scanner; accepts the following arguments.
Only <parameter>function</parameter> is required;
the rest are optional:
</para>

<variablelist>
  <varlistentry>
  <term><parameter>function</parameter></term>
  <listitem>
<para>
A function which can process ("scan")
a given Node (usually a file)
and return a list of Nodes
representing any implicit
dependencies (usually files) which will be tracked
for the Node.
The function must accept three required arguments,
<parameter>node</parameter>,
<parameter>env</parameter> and
<parameter>path</parameter>,
and an optional fourth,
<parameter>arg</parameter>.
<parameter>node</parameter> is
the internal &SCons; node representing the file to scan,
<parameter>env</parameter> is the &consenv; to use during
the scan, and <parameter>path</parameter> is a tuple
of directories that can be searched for files,
as generated by the optional scanner
<xref linkend="path_function"/>.
If the <xref linkend="scanner-argument"/>
parameter was supplied when the Scanner object was created,
it is passed as the <parameter>arg</parameter> parameter
to the scanner function when it is called.
Since <parameter>argument</parameter> is optional,
the scanner function <emphasis>may</emphasis> be
called without an <parameter>arg</parameter> parameter.
</para>

<para>
The scanner function can make use of
<function>str</function>(<parameter>node</parameter>)
to fetch the name of the file,
<parameter>node</parameter>.<methodname>dir</methodname>
to fetch the directory the file is in,
<parameter>node</parameter>.<methodname>get_contents</methodname>()
to fetch the contents of the file as bytes or
<parameter>node</parameter>.<methodname>get_text_contents</methodname>()
to fetch the contents of the file as text.
</para>

<para>
The scanner function should account for any directories
listed in the <parameter>path</parameter> parameter
when determining the existence of possible dependencies.
External tools such as the C/C++ preprocessor are given
lists of directories to search for source file inclusion directives
(e.g.  <literal>#include "myheader.h"</literal>).
That list is generated from the relevant path variable
(e.g. &cv-link-CPPPATH; for C/C++). The Scanner can be
directed to pass the same list on to the scanner function
via the <parameter>path</parameter> parameter so it can
search in the same places.
The Scanner is enabled to pass this list via the
<xref linkend="path_function"/> argument at Scanner creation time.
</para>

<para>
Instead of a scanner function, you can supply a dictionary as the
<parameter>function</parameter> parameter.
The dictionary must map keys (such as file suffixes)
to other Scanner objects.
A Scanner created this way serves as a dispatcher:
the Scanner's <xref linkend="skeys"/> parameter is
automatically populated with the dictionary's keys,
indicating that the Scanner handles Nodes which would be
selected by those keys; the mapping is then used to pass
the file on to a different Scanner that would not have been
selected to handle that Node based on its
own <parameter>skeys</parameter>.
</para>

<para>
Note that the file to scan is
<emphasis>not</emphasis>
guaranteed to exist at the time the scanner is called -
it could be a generated file which has not been generated yet -
so the scanner function must be tolerant of that.
</para>

<para>
While many scanner functions operate on source code files by
looking for known patterns in the code, they can really
do anything they need to.
For example, the &b-link-Program; Builder is assigned a
<xref linkend="target_scanner"/> which examines the
list of libraries supplied for the build (&cv-link-LIBS;)
and decides whether to add them as dependencies,
it does not look <emphasis>inside</emphasis> the built binary.
</para>

<para>
It is up to the scanner function to decide whether or not to
generate an &SCons; dependency for candidates identified by scanning.
Dependencies are a key part of &SCons; operation,
enabling both rebuild determination and correct ordering of builds.
It is particularly important that generated files which are
dependencies are added into the Node graph,
or use-before-create failures are likely.
However, not everything may need to be tracked as a dependency.
In some cases, implementation-provided header files change
infrequently but are included very widely,
so tracking them in the &SCons; node graph could become quite
expensive for limited benefit -
consider for example the C standard header file
<filename>string.h</filename>.
The scanner function is not passed any special information
to help make this choice, so the decision-making encoded
in the scanner function must be carefully considered.
</para>

  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>name</parameter></term>
  <listitem>
<para>The name to use for the Scanner.
This is mainly used to identify the Scanner internally.
The default value is <literal>"NONE"</literal>.</para>
  </listitem>
  </varlistentry>

  <varlistentry id="scanner-argument">
  <term><parameter>argument</parameter></term>
  <listitem>
<para>If specified,
will be passed to the scanner function
<parameter>function</parameter>
and the path function
<parameter>path_function</parameter>
when called,
as the optional parameter each of those functions takes.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="skeys">
  <term><parameter>skeys</parameter></term>
  <listitem>
<para>Scanner key(s) indicating the file types
this scanner is associated with.
Used internally to select an appropriate scanner.
In the usual case of scanning for file names,
this argument will be a list of suffixes
for the different file types that this
Scanner knows how to scan.
If <parameter>skeys</parameter> is a string,
it will be expanded into a list by the current environment.
</para>
  </listitem>
  </varlistentry>

  <varlistentry id="path_function">
  <term><parameter>path_function</parameter></term>
  <listitem>
<para>
If specified, a function to generate paths to pass to
the scanner function to search while generating dependencies.
The function must take five arguments:
a &consenv;,
a Node for the directory containing
the &SConscript; file in which
the first target was defined,
a list of target nodes,
a list of source nodes,
and the value of <parameter>argument</parameter>
if it was supplied when the Scanner was created
(since <parameter>argument</parameter> is optional,
the function may be called without this argument,
the <parameter>path_function</parameter>
should be prepared for this).
Must return a tuple of directories
that can be searched for files to be returned
by this Scanner object.
</para>

<para>
The &f-link-FindPathDirs;
function can be called to return a ready-made
<parameter>path_function</parameter>
for a given &consvar; name,
which is often easier than writing your own function from scratch.
For example,
<userinput>path_function=FindPathDirs('CPPPATH')</userinput>
means the scanner function will be called with the paths extracted
from &cv-CPPPATH; in the &consenv; <parameter>env</parameter>,
and passed as the <parameter>path</parameter> parameter
to the scanner function.
</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>node_class</parameter></term>
  <listitem>
<para>The class of Node that should be returned
by this Scanner object.
Any strings or other objects returned
by the scanner function
that are not of this class
will be run through the function
supplied by the
<parameter>node_factory</parameter> argument.
A value of <constant>None</constant> can
be supplied to indicate no conversion;
the default is to return File nodes.
</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>node_factory</parameter></term>
  <listitem>
<para>A &Python; function that will take a string
or other object
and turn it into the appropriate class of Node
to be returned by this Scanner object,
as indicated by <parameter>node_class</parameter>.
</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>scan_check</parameter></term>
  <listitem>
<para>A Python function that takes two arguments,
a Node (file) and a &consenv;,
and returns whether the
Node should, in fact,
be scanned for dependencies.
This check can be used to eliminate unnecessary
calls to the scanner function when,
for example, the underlying file
represented by a Node does not yet exist.</para>
  </listitem>
  </varlistentry>

  <varlistentry>
  <term><parameter>recursive</parameter></term>
  <listitem>
<para>
Specifies whether this scanner should be re-invoked
on the dependency files returned by the scanner.
If omitted, the Node subsystem will
only invoke the scanner on the file being scanned
and not recurse.
Recursion is needed when the files returned by the
scanner may themselves contain further file dependencies,
as in the case of preprocessor <literal>#include</literal> lines.
A value that evaluates true enables recursion;
<emphasis>recursive</emphasis>
may be a callable function,
in which case it will be called with a list of
Nodes found and
should return a list of Nodes
that should be scanned recursively;
this can be used to select a specific subset of
Nodes for additional scanning.</para>
  </listitem>
  </varlistentry>
</variablelist>

<para>
Once created, a Scanner can be added to an environment
by setting it in the &cv-link-SCANNERS; list,
which automatically triggers &SCons; to also add it
to the environment as a method.
However, usually a scanner is not truly standalone, but needs to
be plugged in to the existing selection mechanism for
deciding how to scan source files based on filename extensions.
For this, &SCons; has a global
<classname>SourceFileScanner</classname>
object that is used by
the &b-link-Object;, &b-link-SharedObject; and &b-link-StaticObject;
builders to decide
which scanner should be used.
You can use the
<methodname>SourceFileScanner.add_scanner()</methodname>
method to add your own Scanner object
to the
&SCons;
infrastructure
that builds target programs or
libraries from a list of
source files of different types:</para>

<programlisting language="python">
def xyz_scan(node, env, path):
    contents = node.get_text_contents()
    # Scan the contents and return the included files.

XYZScanner = Scanner(xyz_scan)

SourceFileScanner.add_scanner('.xyz', XYZScanner)

env.Program('my_prog', ['file1.c', 'file2.f', 'file3.xyz'])
</programlisting>

</refsect2>

<refsect2 id='tool_modules'>
<title>Tool Modules</title>

<para>
Custom tools can be added to a project either by
placing them in the <filename>site_tools</filename> subdirectory
of a configured site directory,
or in a location specified by the
<parameter>toolpath</parameter> keyword argument to &f-link-Environment;.
You have to arrange to call a tool to put it into effect,
either as part of the list given to the <parameter>tools</parameter>
keyword argument at &consenv; initialization,
or by calling &f-link-env-Tool;.
</para>

<para>
The <parameter>toolpath</parameter> parameter
takes a list of path strings,
and the <parameter>tools</parameter> parameter
takes a list of tools, which are often strings:
</para>

<programlisting language="python">
env = Environment(tools=['default', 'foo'], toolpath=['tools'])
</programlisting>

<para>
This looks for a tool specification module <literal>foo</literal>
in directory <filename>tools</filename> and in the standard locations,
as well as using the ordinary default tools for the platform.
</para>

<para>
When looking up tool specification modules,
directories specified via <parameter>toolpath</parameter> are
considered before the existing tool path
(<filename>site_tools</filename> subdirectories
of the default or specified site directories),
which are in turn considered before built-in tools.
For example, adding
a tool specification module <filename>gcc.py</filename> to the toolpath
directory would override the built-in &t-link-gcc; tool.
The <parameter>toolpath</parameter> is saved in the environment
and will be used by subsequent calls to the &f-link-env-Tool; method,
as well as by &f-link-env-Clone;.
</para>

<programlisting language="python">
base = Environment(toolpath=['custom_path'])
derived = base.Clone(tools=['custom_tool'])
derived.CustomBuilder()
</programlisting>

<para>
A tool specification module is a form of &Python; module,
looked up internally using the &Python; import mechanism,
so a tool can consist either
of a single &Python; file taking the name of the tool
(e.g. <filename>mytool.py</filename>) or a directory taking
the name of the tool (e.g. <filename>mytool/</filename>)
which contains at least an <filename>__init__.py</filename> file.
A tool specification module has two required entry points:
</para>

<variablelist>
  <varlistentry>
    <term><function>generate</function>(<parameter>env, **kwargs</parameter>)</term>
    <listitem>
<para>Modify the &consenv; <parameter>env</parameter>
to set up necessary &consvars;, Builders, Emitters, etc.,
so the facilities represented by the tool can be executed.
Take care not to overwrite &consvars; which may
have been explicitly set by the user;
retain and/or append instead. For example:
</para>
<programlisting language="python">
def generate(env):
    ...
    if 'MYTOOL' not in env:
        env['MYTOOL'] = env.Detect("mytool")
    flags = env.get('MYTOOLFLAGS', SCons.Util.CLVar())
    env.AppendUnique(MYTOOLFLAGS='--myarg')
    ...
</programlisting>

<para>The <function>generate</function> function
may use any keyword arguments
that the user supplies via <parameter>kwargs</parameter>
to vary its initialization.</para>
    </listitem>
  </varlistentry>
  <varlistentry>
    <term><function>exists</function>(<parameter>env</parameter>)</term>
    <listitem>
<para>Return a truthy value if the tool can
be called in the context of <parameter>env</parameter>,
else return a falsy value.
Usually this means looking up one or more
known programs using the <varname>PATH</varname> from the
supplied <parameter>env</parameter>, but the tool can
make the <emphasis>exists</emphasis> decision in any way it chooses.
</para>
    </listitem>
  </varlistentry>
</variablelist>

<note>
<para>
At the moment, user-added tools do not automatically have their
<function>exists</function> function called.
As a result, it is recommended that the <function>generate</function>
function be defensively coded - that is, do not rely on any
necessary existence checks already having been performed.
This is expected to be a temporary limitation,
and the <function>exists</function> function should still be provided.
</para>
</note>

<para>An element of the <parameter>tools</parameter> list may also
be a function or other callable object
(including a Tool object returned by a previous call to
&f-link-Tool;) in which case the &f-link-Environment; function
will directly call that object
to update the new &consenv;.
No tool lookup is done in this case.
</para>

<programlisting language="python">
def my_tool(env):
    env['XYZZY'] = 'xyzzy'

env = Environment(tools=[my_tool])
</programlisting>

<para>An element of the <parameter>tools</parameter> list
may also be a two-element list or tuple of the form
<literal>(toolname, kw_dict)</literal>.
SCons searches for the tool specification module
<parameter>toolname</parameter>
as described above,
and passes <parameter>kw_dict</parameter>,
which must be a dictionary,
as keyword arguments to the tool's
<function>generate</function> function.
The <function>generate</function>
function can use those arguments to modify the tool's behavior
by setting up the environment in different ways
or otherwise changing its initialization.</para>

<programlisting language="python">
# in tools/my_tool.py:
def generate(env, **kwargs):
    # Sets MY_TOOL to the value of keyword 'arg1' or '1' if not supplied
    env['MY_TOOL'] = kwargs.get('arg1', '1')

def exists(env):
    return True

# in SConstruct:
env = Environment(
    tools=['default', ('my_tool', {'arg1': 'abc'})], toolpath=['tools']
)
</programlisting>

<para>The tool specification (<function>my_tool</function> in the example)
can use the
&cv-link-PLATFORM; variable from
the &consenv; it is passed to customize the tool for different platforms.
</para>

<para>Tools can be "nested" - that is, they
can be located within a subdirectory in the toolpath.
A nested tool name uses a dot to represent a directory separator</para>

<programlisting language="python">
# namespaced builder
env = Environment(ENV=os.environ.copy(), tools=['SubDir1.SubDir2.SomeTool'])
env.SomeTool(targets, sources)

# Search Paths
# SCons\Tool\SubDir1\SubDir2\SomeTool.py
# SCons\Tool\SubDir1\SubDir2\SomeTool\__init__.py
# .\site_scons\site_tools\SubDir1\SubDir2\SomeTool.py
# .\site_scons\site_tools\SubDir1\SubDir2\SomeTool\__init__.py
</programlisting>

</refsect2>
</refsect1>

<refsect1 id='systemspecific_behavior'>
<title>SYSTEM-SPECIFIC BEHAVIOR</title>

<para>&scons; and its configuration files are very portable,
due largely to its implementation in &Python;.
There are, however, a few portability
issues waiting to trap the unwary.</para>

<refsect2 id='c_file_suffix'>
<title>.C File Suffix</title>

<para>&scons; handles the upper-case
<filename>.C</filename>
file suffix differently,
depending on the capabilities of
the underlying system.
On a case-sensitive system
such as Linux or UNIX,
&scons; treats a file with a
<filename>.C</filename>
suffix as a C++ source file.
On a case-insensitive system
such as Windows,
&scons; treats a file with a
<filename>.C</filename>
suffix as a C source file.</para>
</refsect2>

<refsect2 id='f_file_suffix'>
<title>Fortran File Suffixes</title>

<para>
There are several ways source file suffixes impact the
behavior of &SCons; when working with Fortran language code
(not all are system-specific, but they are included here
for completeness).
</para>

<para>
As the Fortran language has evolved through multiple
standards editions, projects might have a need to handle
files from different language generations differently.
To this end, &SCons; dispatches to  a different compiler
dialect setup (expressed as a set of &consvars;)
depending on the file suffix.
By default, all of these setups start out the same,
but individual &consvars; can be modified as needed to tune a given dialect.
Each of these dialects has a tool specification module
whose documentation describes the &consvars; associated
with that dialect: <filename>.f</filename>
(as well as <filename>.for</filename> and <filename>.ftn</filename>)
in &t-link-fortran;; (&consvars; start with <literal>FORTRAN</literal>)
<filename>.f77</filename> in &t-link-f77;;
(&consvars; start with <literal>F77</literal>)
<filename>.f90</filename> in &t-link-f90;;
(&consvars; start with <literal>F90</literal>)
<filename>.f95</filename> in &t-link-f95;;
(&consvars; start with <literal>F95</literal>)
<filename>.f03</filename> in &t-link-f03;;
(&consvars; start with <literal>F03</literal>)
<filename>.f08</filename> in &t-link-f08;
(&consvars; start with <literal>F08</literal>).
</para>

<para>
While &SCons; recognizes multiple internal dialects
based on filename suffixes,
the convention of various available Fortran compilers is
to assign an actual meaning to only two of these suffixes:
<filename>.f</filename>
(as well as <filename>.for</filename> and <filename>.ftn</filename>)
refers to the fixed-format source
code that was the only available option in FORTRAN 77 and earlier,
and <filename>.f90</filename> refers to free-format source code
which became available as of the Fortran 90 standard.
Some compilers recognize suffixes which correspond to Fortran
specifications later than F90 as equivalent to
<filename>.f90</filename> for this purpose,
while some do not - check the documentation for your compiler.
An occasionally suggested policy suggestion is to use only
<filename>.f</filename> and <filename>.f90</filename>
as Fortran filename suffixes.
The fixed/free form determination can usually be controlled
explicitly with compiler flags
(e.g. <option>-ffixed-form</option> for gfortran),
overriding any assumption that may be made based on the source file suffix.
</para>

<para>
The source file suffix does not imply conformance
with the similarly-named Fortran standard - a suffix of
<filename>.f08</filename> does not mean you are compiling
specifically for Fortran 2008.  Normally, compilers
provide command-line options for making this selection
(e.g. <option>-std=f2008</option> for gfortran).
</para>

<para>
For dialects from F90 on (including the generic FORTRAN dialect),
a suffix of <filename>.mod</filename> is recognized for Fortran modules.
These files are a side effect of compiling a Fortran
source file containing module declarations,
and must be available when other code which declares
that it uses the module is processed.
&SCons; does not currently have integrated support for submodules,
introduced in the Fortran 2008 standard -
the invoked compiler will produce results,
but &SCons; will not recognize
<filename>.smod</filename> files as tracked objects.
</para>

<para>
On a case-sensitive system such as Linux or UNIX,
a file with a an upper-cased suffix from the set
<filename>.F</filename>,
<filename>.FOR</filename>,
<filename>.FTN</filename>,
<filename>.F90</filename>,
<filename>.F95</filename>,
<filename>.F03</filename> and
<filename>.F08</filename>
is treated as a Fortran source file
which shall first be run through
the standard C preprocessor.
The lower-cased versions of these suffixes do not
trigger this behavior.
On systems which do not distinguish between upper
and lower case in filenames,
this behavior is not available,
but files suffixed with either
<filename>.FPP</filename>
or <filename>.fpp</filename>
are always passed to the preprocessor first.
This matches the convention of <command>gfortran</command>
from the GNU Compiler Collection,
and also followed by certain other Fortran compilers.
For these two suffixes,
the generic <emphasis>FORTRAN</emphasis> dialect will be selected.
</para>

<para>
&SCons; itself does not invoke the preprocessor,
that is handled by the compiler,
but it adds &consvars; which are applicable to the preprocessor run.
You can see this difference by examining
&cv-link-FORTRANPPCOM; and &cv-link-FORTRANPPCOMSTR;
which are used instead of
&cv-link-FORTRANCOM; and &cv-link-FORTRANCOMSTR; for that dialect.
</para>
</refsect2>

<refsect2 id='windows_cygwin_tools_and_cygwin_python_v'>
<title>Windows: Cygwin Tools and Cygwin Python vs. Windows Pythons</title>

<para>Cygwin supplies a set of tools and utilities
that let users work on a
Windows system using a POSIX-like environment.
The Cygwin tools, including Cygwin &Python;,
do this, in part,
by sharing an ability to interpret POSIX-style path names.
For example, the Cygwin tools
will internally translate a Cygwin path name
like <filename>/cygdrive/c/mydir</filename>
to an equivalent Windows pathname
of <filename>C:/mydir</filename> (equivalent to <filename>C:\mydir</filename>).
</para>

<para>Versions of &Python;
that are built for native Windows execution,
such as the python.org and ActiveState versions,
do not understand the Cygwin path name semantics.
This means that using a native Windows version of &Python;
to build compiled programs using Cygwin tools
(such as &gcc;, &bison; and &flex;)
may yield unpredictable results.
"Mixing and matching" in this way
can be made to work,
but it requires careful attention to the use of path names
in your &SConscript; files.</para>

<para>In practice, users can sidestep
the issue by adopting the following guidelines:
When using Cygwin's &gcc; for compiling,
use the Cygwin-supplied &Python; interpreter
to run &scons;;
when using &MSVC;
(or some other "native" Windows compiler)
use the python.org, Microsoft Store, ActiveState or other
native version of &Python; to run &scons;.
</para>

<para>
This discussion largely applies to the msys2 environment
as well (with the use of the mingw compiler toolchain),
in particular the recommendation to use the msys2 version of
&Python; if running &scons; from inside an msys2 shell.
</para>
</refsect2>

<refsect2 id='windows_sconsbat_file'>
<title>Windows: <filename>scons.bat</filename> file</title>

<para>On Windows, if &scons; is executed via a wrapper
<filename>scons.bat</filename> batch file,
there are (at least) two ramifications.
Note this is no longer the default - &scons; installed
via &Python;'s <command>pip</command> installer
will have a <command>scons.exe</command> which does
not have these limitations:
</para>

<para>First, Windows command-line users
that want to use variable assignment
on the command line
may have to put double quotes
around the assignments, otherwise the
Windows command shell will consume those as
arguments to itself, not to &scons;:</para>

<screen>
<userinput>scons "FOO=BAR" "BAZ=BLEH"</userinput>
</screen>

<para>Second, the Cygwin shell does not
recognize typing <userinput>scons</userinput>
at the command line prompt as referring to this wrapper.
You can work around this either by executing
<userinput>scons.bat</userinput>
(including the extension)
from the Cygwin command line,
or by creating a wrapper shell
script named
<filename>scons</filename> which
invokes <filename>scons.bat</filename>.
</para>

</refsect2>

<refsect2 id='mingw'>
<title>MinGW</title>

<para>The MinGW <filename>bin</filename>
directory must be in your <envar>PATH</envar>
environment variable or the
<varname>['ENV']['PATH']</varname> &consvar; for &scons;
to detect and use the MinGW tools. When running under the native Windows
&Python; interpreter, &scons; will prefer the MinGW tools over the Cygwin
tools, if they are both installed, regardless of the order of the bin
directories in the <envar>PATH</envar> variable.
If you have both MSVC and MinGW
installed and you want to use MinGW instead of MSVC,
then you must explicitly tell &scons; to use MinGW by passing
<code>tools=['mingw']</code>
to the &Environment; function, because &scons; will prefer the MSVC tools
over the MinGW tools.</para>

</refsect2>
</refsect1>

<!-- Removed in favor of scons-cookbook.readthedocs.io,
     but leave here for the time being...

<refsect1 id='examples'>
<title>EXAMPLES</title>

<para>To help you get started using &scons;,
this section contains a brief overview of some common tasks.
See the &SCons; User Guide for many more examples.
</para>


<refsect2 id='basic_compilation_from_a_single_source_f'>
<title>Basic Compilation From a Single Source File</title>

<programlisting language="python">
env = Environment()
env.Program(target='foo', source='foo.c')
</programlisting>

<para>Note:  Build the file by specifying
the target as an argument
(<userinput>scons foo</userinput> or <userinput>scons foo.exe</userinput>)
or by specifying the current directory as the target
(<userinput>scons .</userinput>).</para>

</refsect2>

<refsect2 id='basic_compilation_from_multiple_source_f'>
<title>Basic Compilation From Multiple Source Files</title>

<programlisting language="python">
env = Environment()
env.Program(target='foo', source=Split('f1.c f2.c f3.c'))
</programlisting>

</refsect2>

<refsect2 id='setting_a_compilation_flag'>
<title>Setting a Compilation Flag</title>

<programlisting language="python">
env = Environment(CCFLAGS='-g')
env.Program(target='foo', source='foo.c')
</programlisting>

</refsect2>

<refsect2 id='search_the_local_directory_for_h_files'>
<title>Search The Local Directory For .h Files</title>

<para>Note:  You do
<emphasis>not</emphasis>
need to set <envar>CCFLAGS</envar> to specify
<option>-I</option> options by hand.
&scons; will construct the right <option>-I</option>
options from the contents of <envar>CPPPATH.</envar></para>

<programlisting language="python">
env = Environment(CPPPATH=['.'])
env.Program(target='foo', source='foo.c')
</programlisting>

</refsect2>

<refsect2 id='search_multiple_directories_for_h_files'>
<title>Search Multiple Directories For .h Files</title>

<programlisting language="python">
env = Environment(CPPPATH=['include1', 'include2'])
env.Program(target='foo', source='foo.c')
</programlisting>

</refsect2>

<refsect2 id='building_a_static_library'>
<title>Building a Static Library</title>

<programlisting language="python">
env = Environment()
env.StaticLibrary(target='foo', source=Split('l1.c l2.c'))
env.StaticLibrary(target='bar', source=['l3.c', 'l4.c'])
</programlisting>

</refsect2>

<refsect2 id='building_a_shared_library'>
<title>Building a Shared Library</title>

<programlisting language="python">
env = Environment()
env.SharedLibrary(target='foo', source=['l5.c', 'l6.c'])
env.SharedLibrary(target='bar', source=Split('l7.c l8.c'))
</programlisting>

</refsect2>

<refsect2 id='linking_a_local_library_into_a_program'>
<title>Linking a Local Library Into a Program</title>

<programlisting language="python">
env = Environment(LIBS='mylib', LIBPATH=['.'])
env.Library(target='mylib', source=Split('l1.c l2.c'))
env.Program(target='prog', source=['p1.c', 'p2.c'])
</programlisting>

</refsect2>

<refsect2 id='defining_your_own_builder_object'>
<title>Defining Your Own Builder Object</title>

<para>Notice that when you invoke the Builder,
you can leave off the target file suffix,
and &scons; will add it automatically.</para>

<programlisting language="python">
bld = Builder(
    action='pdftex &lt; $SOURCES &gt; $TARGET',
    suffix='.pdf',
    src_suffix='.tex'
)
env = Environment(BUILDERS={'PDFBuilder': bld})
env.PDFBuilder(target='foo.pdf', source='foo.tex')

# The following creates "bar.pdf" from "bar.tex"
env.PDFBuilder(target='bar', source='bar')
</programlisting>

<para>Note that the above initialization
replaces the default dictionary of Builders,
so this &consenv; can not be used call Builders like
&b-link-Program;, &b-link-Object;, &b-link-StaticLibrary; etc.
See the next example for an alternative.
</para>

</refsect2>

<refsect2 id='adding_your_own_builder_object_to_an_env'>
<title>Adding Your Own Builder Object to an Environment</title>

<programlisting language="python">
bld = Builder(
    action='pdftex &lt; $SOURCES &gt; $TARGET'
    suffix='.pdf',
    src_suffix='.tex'
)
env = Environment()
env.Append(BUILDERS={'PDFBuilder': bld})
env.PDFBuilder(target='foo.pdf', source='foo.tex')
env.Program(target='bar', source='bar.c')
</programlisting>

<para>You also can use other Pythonic techniques to add
to the <envar>BUILDERS</envar> &consvar;, such as:</para>

<programlisting language="python">
env = Environment()
env['BUILDERS]['PDFBuilder'] = bld
</programlisting>

</refsect2>

<refsect2 id='defining_your_own_scanner_object'>
<title>Defining Your Own Scanner Object</title>

<para>The following example shows adding an extremely simple scanner
(<function>kfile_scan</function>)
that doesn't use a search path at all
and simply returns the
file names present on any
<literal>include</literal>
lines in the scanned file.
This would implicitly assume that all included
files live in the top-level directory:</para>

<programlisting language="python">
import re

include_re = re.compile(r'^include\s+(\S+)$', re.M)

def kfile_scan(node, env, path, arg):
    contents = node.get_text_contents()
    includes = include_re.findall(contents)
    return env.File(includes)

kscan = Scanner(
    name='kfile',
    function=kfile_scan,
    argument=None,
    skeys=['.k'],
)

scanners = DefaultEnvironment()['SCANNERS']
scanners.append(kscan)
env = Environment(SCANNERS=scanners)

env.Command('foo', 'foo.k', 'kprocess &lt; $SOURCES &gt; $TARGET')

bar_in = File('bar.in')
env.Command('bar', bar_in, 'kprocess $SOURCES &gt; $TARGET')
bar_in.target_scanner = kscan
</programlisting>

<para>It is important to note that you
have to return a list of File nodes from the scan function, simple
strings for the file names won't do. As in the examples shown here,
you can use the &f-link-env-File;
function of your current &consenv; in order to create nodes on the fly from
a sequence of file names with relative paths.</para>

<para>Here is a similar but more complete example that adds
a scanner which searches
a path of directories
(specified as the
<envar>MYPATH</envar> &consvar;)
for files that actually exist:</para>

<programlisting language="python">
import re
import os

include_re = re.compile(r'^include\s+(\S+)$', re.M)

def my_scan(node, env, path, arg):
    contents = node.get_text_contents()
    includes = include_re.findall(contents)
    if not includes:
        return []
    results = []
    for inc in includes:
        for dir in path:
            file = str(dir) + os.sep + inc
            if os.path.exists(file):
                results.append(file)
                break
    return env.File(results)

scanner = Scanner(
    name='myscanner',
    function=my_scan,
    argument=None,
    skeys=['.x'],
    path_function=FindPathDirs('MYPATH'),
)

scanners = DefaultEnvironment()['SCANNERS']
scanners.append(scanner)
env = Environment(SCANNERS=scanners, MYPATH=['incs'])

env.Command('foo', 'foo.x', 'xprocess &lt; $SOURCES &gt; $TARGET')
</programlisting>

<para>The
&f-link-FindPathDirs;
function used in the previous example returns a function
(actually a callable &Python; object)
that will return a list of directories
specified in the
<envar>MYPATH</envar>
&consvar;. It lets &scons; detect the file
<filename>incs/foo.inc</filename>,
even if
<filename>foo.x</filename>
contains the line
<literal>include foo.inc</literal>
only.
If you need to customize how the search path is derived,
you would provide your own
<parameter>path_function</parameter>
argument when creating the Scanner object,
as follows:</para>

<programlisting language="python">
# MYPATH is a list of directories to search for files in
def pf(env, dir, target, source, arg):
    top_dir = Dir('#').abspath
    results = []
    if 'MYPATH' in env:
        for p in env['MYPATH']:
            results.append(top_dir + os.sep + p)
    return results


scanner = Scanner(
    name='myscanner',
    function=my_scan,
    argument=None,
    skeys=['.x'],
    path_function=pf
)
</programlisting>

</refsect2>

<refsect2 id='creating_a_hierarchical_build'>
<title>Creating a Hierarchical Build</title>

<para>Notice that the file names specified in a subdirectory's
&SConscript; file are relative to that subdirectory.</para>

<para><filename>SConstruct</filename>:</para>

<programlisting language="python">
env = Environment()
env.Program(target='foo', source='foo.c')

SConscript('sub/SConscript')
</programlisting>

<para><filename>sub/SConscript</filename>:</para>

<programlisting language="python">
env = Environment()
# Builds sub/foo from sub/foo.c
env.Program(target='foo', source='foo.c')

SConscript('dir/SConscript')
</programlisting>

<para><filename>sub/dir/SConscript</filename>:</para>

<programlisting language="python">
env = Environment()
# Builds sub/dir/foo from sub/dir/foo.c
env.Program(target='foo', source='foo.c')
</programlisting>

</refsect2>

<refsect2 id='sharing_variables_between_sconscript_fil'>
<title>Sharing Variables Between SConscript Files</title>

<para>You must explicitly call &f-link-Export; and &f-link-Import;
for variables that
you want to share between &SConscript; files.</para>

<para><filename>SConstruct</filename>:</para>

<programlisting language="python">
env = Environment()
env.Program(target='foo', source='foo.c')

Export("env")
SConscript('subdirectory/SConscript')
</programlisting>

<para><filename>subdirectory/SConscript</filename>:</para>

<programlisting language="python">
Import("env")
env.Program(target='foo', source='foo.c')
</programlisting>

</refsect2>

<refsect2 id='building_multiple_variants_from_the_same'>
<title>Building Multiple Variants From the Same Source</title>

<para>Use the <parameter>variant_dir</parameter> keyword argument to
the &f-link-SConscript; function to establish
one or more separate variant build directory trees
for a given source directory:</para>

<para><filename>SConstruct</filename>:</para>

<programlisting language="python">
cppdefines = ['FOO']
Export("cppdefines")
SConscript('src/SConscript', variant_dir='foo')

cppdefines = ['BAR']
Export("cppdefines")
SConscript('src/SConscript', variant_dir='bar')
</programlisting>

<para><filename>src/SConscript</filename>:</para>

<programlisting language="python">
Import("cppdefines")
env = Environment(CPPDEFINES=cppdefines)
env.Program(target='src', source='src.c')
</programlisting>

<para>Note the use of the &f-link-Export; method
to set the <varname>cppdefines</varname> variable to a different
value each time we call the &f-link-SConscript; function.</para>

</refsect2>

<refsect2 id='hierarchical_build_of_two_libraries_link'>
<title>Hierarchical Build of Two Libraries Linked With a Program</title>

<para><filename>SConstruct</filename>:</para>

<programlisting language="python">
env = Environment(LIBPATH=['#libA', '#libB'])
Export('env')
SConscript('libA/SConscript')
SConscript('libB/SConscript')
SConscript('Main/SConscript')
</programlisting>

<para><filename>libA/SConscript</filename>:</para>

<programlisting language="python">
Import('env')
env.Library('a', Split('a1.c a2.c a3.c'))
</programlisting>

<para><filename>libB/SConscript</filename>:</para>

<programlisting language="python">
Import('env')
env.Library('b', Split('b1.c b2.c b3.c'))
</programlisting>

<para><filename>Main/SConscript</filename>:</para>

<programlisting language="python">
Import('env')
e = env.Clone(LIBS=['a', 'b'])
e.Program('foo', Split('m1.c m2.c m3.c'))
</programlisting>

<para>The <literal>#</literal> in the <envar>LIBPATH</envar>
directories specify that they're relative to the
top-level directory, so they don't turn into
<filename>Main/libA</filename> when they're
used in <filename>Main/SConscript</filename></para>

<para>Specifying only 'a' and 'b' for the library names
allows &scons; to attach the appropriate library
prefix and suffix for the current platform in
creating the library filename
(for example, <filename>liba.a</filename> on POSIX systems,
<filename>a.lib</filename> on Windows).</para>

</refsect2>

<refsect2 id='customizing_construction_variables_from_'>
<title>Customizing &consvars; from the command line.</title>

<para>The following would allow the C compiler to be specified on the command
line or in the file <filename>custom.py</filename>.</para>

<programlisting language="python">
vars = Variables('custom.py')
vars.Add('CC', 'The C compiler.')
env = Environment(variables=vars)
Help(vars.GenerateHelpText(env))
</programlisting>

<para>The user could specify the C compiler on the command line:</para>

<screen>
<userinput>scons "CC=my_cc"</userinput>
</screen>

<para>or in the <filename>custom.py</filename> file:</para>

<programlisting language="python">
CC = 'my_cc'
</programlisting>

<para>or get documentation on the options:</para>

<screen>
$ <userinput>scons -h</userinput>

CC: The C compiler.
    default: None
    actual: cc
</screen>

</refsect2>

<refsect2 id='using_microsoft_visual_c_precompiled_hea'>
<title>Using &MSVC; precompiled headers</title>

<para>Since <filename>windows.h</filename> includes everything
and the kitchen sink, it can take quite
some time to compile it over and over again for a bunch of object files, so
Microsoft provides a mechanism to compile a set of headers once and then
include the previously compiled headers in any object file. This
technology is called precompiled headers (<firstterm>PCH</firstterm>).
The general recipe is to create a
file named <filename>StdAfx.cpp</filename>
that includes a single header named <filename>StdAfx.h</filename>,
and then include every header you want to precompile in
<filename>StdAfx.h</filename>,
and finally include <filename>"StdAfx.h</filename>
as the first header in all the source files you are
compiling to object files. For example:</para>

<para><filename>StdAfx.h</filename>:</para>

<programlisting language="C++">
#include &lt;windows.h&gt;
#include &lt;my_big_header.h&gt;
</programlisting>

<para><filename>StdAfx.cpp</filename>:</para>

<programlisting language="C++">
#include &lt;StdAfx.h&gt;
</programlisting>

<para><filename>Foo.cpp</filename>:</para>

<programlisting language="C++">
#include &lt;StdAfx.h&gt;

/* do some stuff */
</programlisting>

<para><filename>Bar.cpp</filename>:</para>

<programlisting language="C++">
#include &lt;StdAfx.h&gt;

/* do some other stuff */
</programlisting>

<para><filename>SConstruct</filename>:</para>

<programlisting language="python">
env=Environment()
env['PCHSTOP'] = 'StdAfx.h'
env['PCH'] = env.PCH('StdAfx.cpp')[0]
env.Program('MyApp', ['Foo.cpp', 'Bar.cpp'])
</programlisting>

<para>For more information see the documentation for the &b-link-PCH; builder,
and the &cv-link-PCH; and &cv-link-PCHSTOP; &consvars;.
To learn about the details of precompiled
headers consult the MSDN documentation for
<option>/Yc</option>, <option>/Yu</option>, and <option>/Yp</option>.</para>

</refsect2>

<refsect2 id='using_microsoft_visual_c_external_debugg'>
<title>Using &MSVC; external debugging information</title>

<para>Since including debugging information in programs and shared libraries can
cause their size to increase significantly, Microsoft provides a mechanism
for including the debugging information in an external file called a
<firstterm>PDB</firstterm> file.
&scons; supports PDB files through the &cv-PDB; &consvar;.</para>

<para><filename>SConstruct</filename>:</para>

<programlisting language="python">
env=Environment()
env['PDB'] = 'MyApp.pdb'
env.Program('MyApp', ['Foo.cpp', 'Bar.cpp'])
</programlisting>

<para>For more information see the documentation for the
&cv-link-PDB; &consvar;.</para>

</refsect2>
</refsect1 -->

<refsect1 id='environment'>
<title>ENVIRONMENT</title>

<para>In general, &scons; is not controlled by environment
variables set in the shell used to invoke it, leaving it
up to the &SConscript; file author to import those if desired.
However, the following variables are imported by
&scons; itself if set:
</para>

<variablelist>
  <varlistentry>
    <term><envar>SCONS_LIB_DIR</envar></term>
    <listitem>
<para>Specifies the directory that contains the &scons;
&Python; module directory. Normally &scons; can deduce this,
but in some circumstances, such as working with a source
release, it may be necessary to specify
(for example,
<filename>/home/aroach/scons-src-0.01/src/engine</filename>).</para>
    </listitem>
  </varlistentry>

  <varlistentry id="v-SCONSFLAGS">
    <term><envar>SCONSFLAGS</envar></term>
    <listitem>
<para>A string containing options that will be used by &scons;
in addition to those passed on the command line.
Can be used to reduce frequent retyping of common options.
The contents of <envar>SCONSFLAGS</envar> are considered
before any passed command line options,
so the command line can be used to override
<envar>SCONSFLAGS</envar> options if necessary.
</para>
    </listitem>
  </varlistentry>

  <varlistentry>
    <term><envar>SCONS_CACHE_MSVC_CONFIG</envar></term>
    <listitem>
<para>(Windows only). If set, save the shell environment variables
generated when setting up the &MSVC; compiler
(and/or Build Tools) to a cache file, to give these settings
persistence across &scons; invocations.
Generating this information is relatively expensive,
so using this option may aid performance where &scons; is run often,
such as Continuous Integration setups.</para>

<para>If set to a True-like value (<literal>"1"</literal>,
<literal>"true"</literal> or
<literal>"True"</literal>) will cache to a file named
<filename>scons_msvc_cache.json</filename> in the user's home directory.
If set to a pathname, will use that pathname for the cache.</para>

<para>Note: this implementation may still be somewhat fragile.
In case of problems, remove the cache file - recreating with
fresh info normally resolves any issues.
&SCons; ignores failures reading or writing the cache file
and will silently revert to non-cached behavior in such cases.
</para>

<para><emphasis>New in 3.1 (experimental).
The default cache file name was changed to
its present value in 4.4, and contents were expanded.</emphasis>
</para>
    </listitem>
  </varlistentry>

  <varlistentry>
    <term><envar>QTDIR</envar></term>
    <listitem>
<para>If using the &t-link-qt; tool, this is the path to
the Qt installation to build against. &SCons; respects this
setting because it is a long-standing convention in the Qt world,
where multiple Qt installations are possible.</para>
    </listitem>
  </varlistentry>
</variablelist>
</refsect1>

<refsect1 id='see_also'>
<title>SEE ALSO</title>

  <simplelist type="vert">
  <member>
    The SCons User Guide at
    <ulink url="https://scons.org/doc/production/HTML/scons-user.html"/>
 </member>
  <member>The SCons Design Document (old)</member>
  <member>
    The SCons Cookbook at
    <ulink url="https://scons-cookbook.readthedocs.io"/>
    for examples of how to solve various problems with &SCons;.
  </member>
  <member>
    SCons source code
    <ulink url="https://github.com/SCons/scons">
    on GitHub</ulink>
  </member>
  <member>
    The SCons API Reference
    <ulink url="https://scons.org/doc/production/HTML/scons-api/index.html"/>
    (for internal details)
   </member>
  </simplelist>

</refsect1>

<refsect1 id='authors'>
<title>AUTHORS</title>

  <para>Originally: Steven Knight
    <email>knight@baldmt.com</email>
    and Anthony Roach <email>aroach@electriceyeball.com</email>.
  </para>
  <para>
    Since 2010: The SCons Development Team <email>scons-dev@python.org</email>.
  </para>
</refsect1>
</refentry>
</reference>
