('jar', 'JARCOM', JarCom, []),
('rmic', 'RMICCOM', Cat, []),
],
- 'win32' : [('msvc', ['CCCOM', 'SHCCCOM'], CCCom, ['CCFLAGS', 'CPPDEFINES', 'COLOR', 'COLORS', 'PACKAGE']),
+ 'win32' : [('msvc', ['CCCOM', 'SHCCCOM', 'RCCOM'], CCCom, ['CCFLAGS', 'CPPDEFINES', 'COLOR', 'COLORS', 'PACKAGE']),
('mslink', ['LINKCOM', 'SHLINKCOM'], Cat, []),
('mslib', 'ARCOM', Cat, []),
('tar', 'TARCOM', Null, []),
--- /dev/null
+#!/usr/bin/env python
+# -*- Python -*-
+
+import sys
+from math import log, ceil
+from optparse import OptionParser
+import subprocess
+
+# crack the command line
+parser = OptionParser(
+ usage="%prog lower-revision upper-revision test_script [arg1 ...]",
+ description="Binary search for a bug in a SVN checkout")
+(options,script_args) = parser.parse_args()
+
+# make sure we have sufficient parameters
+if len(script_args) < 1:
+ parser.error("Need a lower revision")
+elif len(script_args) < 2:
+ parser.error("Need an upper revision")
+elif len(script_args) < 3:
+ parser.error("Need a script to run")
+
+# extract our starting values
+lower = int(script_args[0])
+upper = int(script_args[1])
+script = script_args[2:]
+
+# print an error message and quit
+def error(s):
+ print >>sys.stderr, "******", s, "******"
+ sys.exit(1)
+
+# update to the specified version and run test
+def testfail(revision):
+ "Return true if test fails"
+ print "Updating to revision", revision
+ if subprocess.call(["svn","up","-qr",str(revision)]) != 0:
+ m = "SVN did not update properly to revision %d"
+ raise RuntimeError(m % revision)
+ return subprocess.call(script,shell=False) != 0
+
+# confirm that the endpoints are different
+print "****** Checking upper bracket", upper
+upperfails = testfail(upper)
+print "****** Checking lower bracket", lower
+lowerfails = testfail(lower)
+if upperfails == lowerfails:
+ error("Upper and lower revisions must bracket the failure")
+
+# binary search for transition
+msg = "****** max %d revisions to test (bug bracketed by [%d,%d])"
+while upper-lower > 1:
+ print msg % (ceil(log(upper-lower,2)), lower, upper)
+
+ mid = int((lower + upper)/2)
+ midfails = testfail(mid)
+ if midfails == lowerfails:
+ lower = mid
+ lowerfails = midfails
+ else:
+ upper = mid
+ upperfails = midfails
+
+# show which revision was first to fail
+if upperfails != lowerfails: lower = upper
+print "The error was caused by revision", lower
# 'issues.xml'. Run this script to translate 'issues.xml' into a CSV
# file named 'editlist.csv'. Upload the CSV into a Google spreadsheet.
-# In the spreadsheet, select the last column and delete it (added by the
-# upload to allow for expansion; we don't need it).
+# In the spreadsheet, select the last column and pick "delete-->column" (it
+# was added by the upload to allow for expansion and we don't need it).
# Select all the columns and pick "align-->top"
# Select the ID and votes columns and pick "align-->right"
# Select the priority column and pick "align-->center"
# The team members
# FIXME: These names really should be external to this script
-team = 'Bill Greg Steven Gary Ken Brandon Sohail Jim'.split()
+team = 'Bill Greg Steven Gary Ken Brandon Sohail Jim David'.split()
team.sort()
# The elements to be picked out of the issue
return v.nodeValue
# Parse the XML issues file and produce a DOM for it
-# FIXME: parameterize the input file name
+import sys
+if len(sys.argv) > 1: xml = sys.argv[1]
+else: xml = 'issues.xml'
from xml.dom.minidom import parse
-xml = parse('issues.xml')
+xml = parse(xml)
# Go through the issues in the DOM, pick out the elements we want,
# and put them in our list of issues.
.\"
.\" __FILE__ __REVISION__ __DATE__ __DEVELOPER__
.\"
+.TH SCONS 1 "__MONTH_YEAR__"
.\" ES - Example Start - indents and turns off line fill
+.rm ES
.de ES
.RS
.nf
..
.\" EE - Example End - ends indent and turns line fill back on
+.rm EE
.de EE
.fi
.RE
..
-.TH SCONS 1 "__MONTH_YEAR__"
.SH NAME
scons \- a software construction tool
.SH SYNOPSIS
]
.SH DESCRIPTION
-The
-.B scons
+The
+.B scons
utility builds software (or other files) by determining which
component pieces must be rebuilt and executing the necessary commands to
rebuild them.
-By default,
-.B scons
-searches for a file named
+By default,
+.B scons
+searches for a file named
.IR SConstruct ,
.IR Sconstruct ,
or
(in that order) in the current directory and reads its
configuration from the first file found.
An alternate file name may be
-specified via the
+specified via the
.B -f
option.
can scan known input files automatically for dependency
information (for example, #include statements
in C or C++ files) and will rebuild dependent files appropriately
-whenever any "included" input file changes.
+whenever any "included" input file changes.
.B scons
supports the
ability to define new scanners for unknown input file types.
(along with any derived files on which they depend).
Specifying "cleanup" targets in SConscript files is not usually necessary.
-The
+The
.B -c
flag removes all files
necessary to build the specified target:
function.
A subset of a hierarchical tree may be built by
-remaining at the top-level directory (where the
+remaining at the top-level directory (where the
.I SConstruct
file lives) and specifying the subdirectory as the target to be
built:
or by changing directory and invoking scons with the
.B -u
option, which traverses up the directory
-hierarchy until it finds the
+hierarchy until it finds the
.I SConstruct
file, and then builds
targets relatively to the current subdirectory:
.B scons
can maintain a cache of target (derived) files that can
be shared between multiple builds. When caching is enabled in a
-SConscript file, any target files built by
+SConscript file, any target files built by
.B 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
-.BR --cache-force ,
+.BR --cache-force ,
.BR --cache-disable ,
and
.B --cache-show
and the PharLap ETS compiler.
On OS/2 systems,
.B scons
-searches in order for the
+searches in order for the
OS/2 compiler,
the GCC tool chain,
and the Microsoft Visual C++ tools,
Environment construction variables.
.SH OPTIONS
-In general,
-.B scons
+In general,
+.B scons
supports the same command-line options as GNU
-.BR make ,
-and many of those supported by
+.BR make ,
+and many of those supported by
.BR cons .
.TP
and a necessary test does not
yet have any results in the cache.
-.TP
+.TP
.RI "-C" " directory" ", --directory=" directory
-Change to the specified
+Change to the specified
.I directory
-before searching for the
+before searching for the
.IR SConstruct ,
.IR Sconstruct ,
or
.I sconstruct
file, or doing anything
-else. Multiple
+else. Multiple
.B -C
options are interpreted
relative to the previous one, and the right-most
.B -C
option wins. (This option is nearly
-equivalent to
+equivalent to
.BR "-f directory/SConstruct" ,
except that it will search for
.IR SConstruct ,
-.IR Sconstruct ,
+.IR Sconstruct ,
or
.I sconstruct
in the specified directory.)
.TP
--debug=includes
-Print the include tree after each top-level target is built.
+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:
$ scons --debug=presub
Building myprog.o with action(s):
$SHCC $SHCFLAGS $SHCCFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES
-...
+\&...
.EE
.TP
.TP
.RI --duplicate= ORDER
There are three ways to duplicate files in a build tree: hard links,
-soft (symbolic) links and copies. The default behaviour of SCons is to
+soft (symbolic) links and copies. The default behaviour of SCons is to
prefer hard links to soft links to copies. You can specify different
behaviours with this option.
-.IR ORDER
-must be one of
+.IR ORDER
+must be one of
.IR hard-soft-copy
(the default),
.IR soft-hard-copy ,
.TP
.RI -f " file" ", --file=" file ", --makefile=" file ", --sconstruct=" file
-Use
-.I file
+Use
+.I file
as the initial SConscript file.
-.TP
+.TP
-h, --help
Print a local help message for this build, if one is defined in
-the SConscript file(s), plus a line that describes the
+the SConscript file(s), plus a line that describes the
.B -H
option for command-line option help. If no local help message
is defined, prints the standard help message about command-line
-i, --ignore-errors
Ignore all errors from commands executed to rebuild files.
-.TP
+.TP
.RI -I " directory" ", --include-dir=" directory
-Specifies a
+Specifies a
.I directory
to search for
-imported Python modules. If several
+imported Python modules. If several
.B -I
options
are used, the directories are searched in the order specified.
--implicit-deps-unchanged
Force SCons to ignore changes in the implicit dependencies.
This causes cached implicit dependencies to always be used.
-This implies
+This implies
.BR --implicit-cache .
.TP
-n, --no-exec, --just-print, --dry-run, --recon
-Q
-s, --silent, --quiet
--s, --silent, --quiet
--taskmastertrace=FILE
--tree=OPTIONS
.EE
.TP
.RI -j " N" ", --jobs=" N
Specifies the number of jobs (commands) to run simultaneously.
-If there is more than one
-.B -j
+If there is more than one
+.B -j
option, the last one is effective.
-.\" ??? If the
-.\" .B -j
+.\" ??? If the
+.\" .B -j
.\" option
.\" is specified without an argument,
-.\" .B scons
+.\" .B scons
.\" will not limit the number of
.\" simultaneous jobs.
.\" .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
+.\" average is at least
.\" .I N
.\" (a floating-point number).
.TP
.RI --max-drift= SECONDS
-Set the maximum expected drift in the modification time of files to
+Set the maximum expected drift in the modification time of files to
.IR SECONDS .
This value determines how long a file must be unmodified
before its cached content signature
No execute. Print the commands that would be executed to build
any out-of-date target files, but do not execute the commands.
-.TP
+.TP
.RI --no-site-dir
Prevents the automatic addition of the standard
.I site_scons
.\" .TP
.\" .RI -o " file" ", --old-file=" file ", --assume-old=" file
-.\" Do not rebuild
+.\" Do not rebuild
.\" .IR file ,
.\" and do
.\" not rebuild anything due to changes in the contents of
.\" .IR file .
-.\" .TP
+.\" .TP
.\" .RI --override " file"
.\" Read values to override specific build environment variables
-.\" from the specified
+.\" from the specified
.\" .IR file .
.\" .TP
.\" -p
.\" After printing, a normal build is performed
.\" as usual, as specified by other command-line options.
.\" This also prints version information
-.\" printed by the
+.\" printed by the
.\" .B -v
.\" option.
.\"
.TP
-S, --no-keep-going, --stop
-Ignored for compatibility with GNU
+Ignored for compatibility with GNU
.BR make .
-.TP
+.TP
.RI --site-dir= dir
Uses the named dir as the site dir rather than the default
.I site_scons
.TP
.RI --stack-size= KILOBYTES
Set the size stack used to run threads to
-.IR KILOBYTES .
+.IR KILOBYTES .
This value determines the stack size of the threads used to run jobs.
These are the threads that execute the actions of the builders for the
nodes that are out-of-date.
.TP
-t, --touch
Ignored for compatibility with GNU
-.BR make .
+.BR make .
(Touching a file to make it
-appear up-to-date is unnecessary when using
+appear up-to-date is unnecessary when using
.BR scons .)
.TP
.TP
-u, --up, --search-up
-Walks up the directory structure until an
+Walks up the directory structure until an
.I SConstruct ,
.I Sconstruct
-or
+or
.I sconstruct
file is found, and uses that
as the top of the directory tree.
.TP
-v, --version
-Print the
+Print the
.B scons
version, copyright information,
list of authors, and any other relevant information.
.TP
--warn=duplicate-environment, --warn=no-duplicate-environment
-Enables or disables warnings about missing SConscript files.
+Enables or disables warnings about attempts to specify a build
+of a target with two different construction environments
+that use the same action.
+These warnings are enabled by default.
.TP
--warn=fortran-cxx-mix, --warn=no-fortran-cxx-mix
.TP
--warn=missing-sconscript, --warn=no-missing-sconscript
-Enables or disables warnings about attempts to specify a build
-of a target with two different construction environments
-that use the same action.
+Enables or disables warnings about missing SConscript files.
These warnings are enabled by default.
.TP
.\"
.\" .TP
.\" .RI -W " file" ", --what-if=" file ", --new-file=" file ", --assume-new=" file
-.\" Pretend that the target
-.\" .I file
+.\" Pretend that the target
+.\" .I file
.\" has been
-.\" modified. When used with the
+.\" modified. When used with the
.\" .B -n
.\" option, this
.\" show you what would be rebuilt if you were to modify that file.
-.\" Without
+.\" Without
.\" .B -n
.\" ... what? XXX
.\"
.\" --warn-undefined-variables
.\" Warn when an undefined variable is referenced.
-.TP
+.TP
.RI -Y " repository" ", --repository=" repository ", --srcdir=" repository
Search the specified repository for any input and target
files not found in the local directory hierarchy. Multiple
.\" XXX Adding this in the future would be a help.
.SS Construction Environments
A construction environment is the basic means by which the SConscript
-files communicate build information to
+files communicate build information to
.BR scons .
-A new construction environment is created using the
-.B Environment
+A new construction environment is created using the
+.B Environment
function:
.ES
.I construction
.IR variables ,
may be set in a construction environment
-either by specifyng them as keywords when the object is created
+either by specifying them as keywords when the object is created
or by assigning them a value after the object is created:
.ES
This is so that any executed commands
that use sockets to connect with other systems
(such as fetching source files from
-external CVS repository specifications like
+external CVS repository specifications like
.BR :pserver:anonymous@cvs.sourceforge.net:/cvsroot/scons )
will work on Windows systems.
(that is, do not begin with
.B /
on POSIX systems
-or
+or
.B \\
on Windows systems,
with or without
executable program
.B bar
(on POSIX systems)
-or
+or
.B bar.exe
(on Windows systems)
from the bar.c source file:
'\" END GENERATED BUILDER DESCRIPTIONS
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.P
All
targets of builder methods automatically depend on their sources.
An explicit dependency can
-be specified using the
-.B Depends
+be specified using the
+.B Depends
method of a construction environment (see below).
In addition,
Except where otherwise noted,
the same-named
construction environment method
-and global function
+and global function
provide the exact same functionality.
The only difference is that,
where appropriate,
include:
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI Action( action ", [" strfunction ", " varlist ])
.TP
.RI env.Action( action ", [" strfunction ", " varlist ])
See the section "Action Objects,"
below, for a complete explanation of the arguments and behavior.
-Note that the
+Note that the
.BR env.Action ()
form of the invocation will expand
construction variables in any arguments strings,
until the Action object is actually used.
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI AddMethod( object, function ", [" name ])
.TP
.RI env.AddMethod( function ", [" name ])
to indicate that the specified long option(s) take(s) an
.I optional
argument.
-When
+When
.B "nargs = '?'"
is passed to the
.BR AddOption ()
.BR GetOption ()
or
.BR env.GetOption ().
-The value may also be set, using
-.BR SetOption ()
-or
-.BR env.SetOption (),
-if conditions in a
-.B SConscript
-require overriding any default value.
-Note, however, that a
-value specified on the command line will
-.I always
-override a value set by any SConscript file.
+\" NOTE: in SCons 1.x or 2.0, user options will be settable, but not yet.
+\" Uncomment this when that works. See tigris issue 2105.
+\" The value may also be set, using
+\" .BR SetOption ()
+\" or
+\" .BR env.SetOption (),
+\" if conditions in a
+\" .B SConscript
+\" require overriding any default value.
+\" Note, however, that a
+\" value specified on the command line will
+\" .I always
+\" override a value set by any SConscript file.
Any specified
.B help=
.EE
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI AddPostAction( target ", " action )
.TP
.RI env.AddPostAction( target ", " action )
can be converted into an Action object
(see below).
+When multiple targets are supplied,
+the action may be called multiple times,
+once after each action that generates
+one or more targets in the list.
+
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI AddPreAction( target ", " action )
.TP
.RI env.AddPreAction( target ", " action )
can be converted into an Action object
(see below).
+When multiple targets are specified,
+the action(s) may be called multiple times,
+once before each action that generates
+one or more targets in the list.
+
+Note that if any of the targets are built in multiple steps,
+the action will be invoked just
+before the "final" action that specifically
+generates the specified target(s).
+For example, when building an executable program
+from a specified source
+.B .c
+file via an intermediate object file:
+
+.ES
+foo = Program('foo.c')
+AddPreAction(foo, 'pre_action')
+.EE
+
+The specified
+.B pre_action
+would be executed before
+.B scons
+calls the link command that actually
+generates the executable program binary
+.BR foo ,
+not before compiling the
+.B foo.c
+file into an object file.
+
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
.RI Alias( alias ", [" targets ", [" action ]])
(This will be officially deprecated some day.)
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI Builder( action ", [" arguments ])
-.TP
+.TP
.RI env.Builder( action ", [" arguments ])
Creates a Builder object for
the specified
See the section "Builder Objects,"
below, for a complete explanation of the arguments and behavior.
-Note that the
+Note that the
.BR env.Builder ()
form of the invocation will expand
construction variables in any arguments strings,
until after the Builder object is actually called.
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI CacheDir( cache_dir )
-.TP
+.TP
.RI env.CacheDir( cache_dir )
Specifies that
.B scons
predict or prohibitively large.
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI Clean( targets ", " files_or_dirs )
-.TP
+.TP
.RI env.Clean( targets ", " files_or_dirs )
This specifies a list of files or directories which should be removed
whenever the targets are specified with the
Examples:
The related
-.BR NoClean ()
+.BR NoClean ()
function overrides calling
.BR Clean ()
for the same target,
.EE
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI Decider( function )
.TP
.RI env.Decider( function )
.EE
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI Default( targets )
.TP
.RI env.Default( targets )
.TP
.RI env.Depends( target ", " dependency )
Specifies an explicit dependency;
-the target file(s) will be rebuilt
-whenever the dependency file(s) has changed.
+the
+.I target
+will be rebuilt
+whenever the
+.I dependency
+has changed.
+Both the specified
+.I target
+and
+.I dependency
+can be a string
+(usually the path name of a file or directory)
+or Node objects,
+or a list of strings or Node objects
+(such as returned by a Builder call).
This should only be necessary
for cases where the dependency
is not caught by a Scanner
.ES
env.Depends('foo', 'other-input-file-for-foo')
+
+mylib = env.Library('mylib.c')
+installed_lib = env.Install('lib', mylib)
+bar = env.Program('bar.c')
+
+# Arrange for the library to be copied into the installation
+# directory before trying to build the "bar" program.
+# (Note that this is for example only. A "real" library
+# dependency would normally be configured through the $LIBS
+# and $LIBPATH variables, not using an env.Depends() call.)
+
+env.Depends(bar, installed_lib)
.EE
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.RI env.Dir( name ", [" directory ])
This returns a Directory Node,
an object that represents the specified directory
-.IR name .
+.IR name .
.I name
-can be a relative or absolute path.
+can be a relative or absolute path.
.I directory
-is an optional directory that will be used as the parent directory.
+is an optional directory that will be used as the parent directory.
If no
.I directory
is specified, the current script's directory is used as the parent.
-If
+If
.I name
is a list, SCons returns a list of Dir nodes.
Construction variables are expanded in
.IP
will print:
.ES
-'$CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
+\&'$CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
.EE
.ES
.RI EnsurePythonVersion( major ", " minor )
.TP
.RI env.EnsurePythonVersion( major ", " minor )
-Ensure that the Python version is at least
-.IR major . minor .
+Ensure that the Python version is at least
+.IR major . minor .
This function will
print out an error message and exit SCons with a non-zero exit code if the
actual Python version is not late enough.
.RI EnsureSConsVersion( major ", " minor ", [" revision ])
.TP
.RI env.EnsureSConsVersion( major ", " minor ", [" revision ])
-Ensure that the SCons version is at least
+Ensure that the SCons version is at least
.IR major.minor ,
or
-.IR major.minor.revision .
+.IR major.minor.revision .
if
.I revision
is specified.
pairs.
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI Execute( action ", [" strfunction ", " varlist ])
.TP
.RI env.Execute( action ", [" strfunction ", " varlist ])
.RI Export( vars )
.TP
.RI env.Export( vars )
-This tells
+This tells
.B scons
to export a list of variables from the current
SConscript file to all other SConscript files.
The exported variables are kept in a global collection,
so subsequent calls to
.BR Export ()
-will over-write previous exports that have the same name.
+will over-write previous exports that have the same name.
Multiple variable names can be passed to
.BR Export ()
as separate arguments or as a list. A dictionary can be used to map
function, below.
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI File( name ", [" directory ])
-.TP
+.TP
.RI env.File( name ", [" directory ])
This returns a
File Node,
an object that represents the specified file
-.IR name .
+.IR name .
.I name
-can be a relative or absolute path.
+can be a relative or absolute path.
.I directory
-is an optional directory that will be used as the parent directory.
+is an optional directory that will be used as the parent directory.
-If
+If
.I name
is a list, SCons returns a list of File nodes.
Construction variables are expanded in
.RI FindFile( file ", " dirs )
.TP
.RI env.FindFile( file ", " dirs )
-Search for
-.I file
-in the path specified by
+Search for
+.I file
+in the path specified by
.IR dirs .
.I file
may be a list of file names or a single file name. In addition to searching
.EE
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI GetBuildFailures()
Returns a list of exceptions for the
actions that failed while
This function provides a way to query the value of
SCons options set on scons command line
(or set using the
-.IR SetOption ()
+.IR SetOption ()
function).
The options supported are:
.RI Help( text )
.TP
.RI env.Help( text )
-This specifies help text to be printed if the
-.B -h
+This specifies help text to be printed if the
+.B -h
argument is given to
.BR scons .
If
.EE
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI Import( vars )
-.TP
+.TP
.RI env.Import( vars )
-This tells
+This tells
.B scons
to import a list of variables into the current SConscript file. This
will import variables that were exported with
.BR Export ()
-or in the
+or in the
.I exports
-argument to
+argument to
.BR SConscript ().
-Variables exported by
+Variables exported by
.BR SConscript ()
have precedence.
-Multiple variable names can be passed to
+Multiple variable names can be passed to
.BR Import ()
as separate arguments or as a list. The variable "*" can be used
to import all variables.
not as separate arguments to
.BR env.MergeFlags ().
-By default,
+By default,
duplicate values are eliminated;
you can, however, specify
.B unique=0
.RI env.NoCache( target ", ...)"
Specifies a list of files which should
.I not
-be cached whenever the
+be cached whenever the
.BR CacheDir ()
method has been activated.
The specified targets may be a list
Builder methods.
Calling
-.BR NoClean ()
+.BR NoClean ()
for a target overrides calling
.BR Clean ()
for the same target,
.BR gtk-config )
and adds the options
to the appropriate construction variables.
-By default,
+By default,
duplicate values are not
added to any construction variables;
you can specify
Any other strings not associated with options
are assumed to be the names of libraries
and added to the
-.B LIBS
+.B LIBS
construction variable.
Examples (all of which produce the same result):
This is so that any executed commands
that use sockets to connect with other systems
(such as fetching source files from
-external CVS repository specifications like
+external CVS repository specifications like
.BR :pserver:anonymous@cvs.sourceforge.net:/cvsroot/scons )
will work on Windows systems.
.EE
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.TP
+.TP
.RI Scanner( function ", [" argument ", " keys ", " path_function ", " node_class ", " node_factory ", " scan_check ", " recursive ])
-.TP
+.TP
.RI env.Scanner( function ", [" argument ", " keys ", " path_function ", " node_class ", " node_factory ", " scan_check ", " recursive ])
Creates a Scanner object for
the specified
.RI name= script
keyword argument.
-The optional
+The optional
.I exports
argument provides a list of variable names or a dictionary of
named values to export to the
.BR Import ()
function to import the variables.
-In effect, the optional
+If the optional
.I variant_dir
-argument causes the files (and subdirectories) in the directory where
-.I script
-resides to be copied to
-.I variant_dir
-and the build performed in
-.IR variant_dir .
-Thus, all of the targets (for example, object files and executables)
-that would normally be built in (or underneath) the directory containing
-.I script
-would actually be built in (or underneath)
-.IR variant_dir .
-See the description of the
-.BR VariantDir ()
-function below for the details and restrictions.
+argument is present, it causes an effect equivalent to
+.BR VariantDir (
+.IR variant_dir ,
+.IR src_dir ,
+.IR duplicate )
+to be executed prior to reading the
+.IR script (s).
+(If
.I variant_dir
-is interpreted relative to the directory
-of the calling SConscript file.
-
-Normally, the source for the variant build is the directory containing
-.IR script .
-If the sources are not in
-.IR script 's
-directory, the optional
+is not present, the
.I src_dir
-argument provides the location of the sources.
+and
+.I duplicate
+arguments are ignored.)
+The
+.I variant_dir
+and
.I src_dir
-is interpreted relative to the directory
+arguments are interpreted relative to the directory
of the calling SConscript file.
-
-By default,
-.B scons
-will link or copy (depending on the platform)
-all the source files into the variant directory tree.
-This behavior may be disabled by setting the optional
-.I duplicate
-argument to 0 (it is set to 1 by default), in which case
-.B scons
-will refer directly to the source files in their source directory
-when building target files.
-See the description for
+If
+.I src_dir
+is not specified, the directory of the calling SConscript file is assumed.
+See the description of the
.BR VariantDir ()
-below for the details and restrictions.
+function below for additional details and restrictions.
-Any variables returned by
-.I script
-using
+Any variables returned by
+.I script
+using
.BR Return ()
will be returned by the call to
-.BR SConscript ().
+.BR SConscript ().
Examples:
SConscript('subdir/SConscript')
foo = SConscript('sub/SConscript', exports='env')
SConscript('dir/SConscript', exports=['env', 'variable'])
-SConscript('src/SConscript', variant_dir='build', duplicate=0)
-SConscript('bld/SConscript', src_dir='src', exports='env variable')
+SConscript('dir/SConscript', exports='env variable')
SConscript(dirs=['sub1', 'sub2'])
SConscript(dirs=['sub3', 'sub4'], name='MySConscript')
.EE
+.ES
+SConscript('bld/SConscript', variant_dir='bld', duplicate=0)
+.EE
+which is equivalent to
+.ES
+VariantDir('bld', '.', duplicate=0)
+SConscript('bld/SConscript')
+.EE
+'\"TODO: SConscript('bld/SConscript', src_dir='src', exports='env variable')
+
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
.RI SConscriptChdir( value )
Declares
.I side_effect
as a side effect of building
-.IR target .
-Both
-.I side_effect
+.IR target .
+Both
+.I side_effect
and
.I target
can be a list, a file name, or a node.
-A side effect is a target that is created
+A side effect is a target file that is created or updated
as a side effect of building other targets.
For example, a Windows PDB
file is created as a side effect of building the .obj
-files for a static library.
+files for a static library,
+and various log files are created updated
+as side effects of various TeX commands.
If a target is a side effect of multiple build commands,
.B scons
will ensure that only one set of commands
for side-effect targets that are built as a result of
multiple build commands.
+Because multiple build commands may update
+the same side effect file,
+by default the
+.I side_effect
+target is
+.I not
+automatically removed
+when the
+.I target
+is removed by the
+.B -c
+option.
+(Note, however, that the
+.I side_effect
+might be removed as part of
+cleaning the directory in which it lives.)
+If you want to make sure the
+.I side_effect
+is cleaned whenever a specific
+.I target
+is cleaned,
+you must specify this explicitly
+with the
+.BR Clean ()
+or
+.BR env.Clean ()
+function.
+
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
.RI SourceCode( entries ", " builder )
by setting a new value.
The optional
.I built_value
-argument can be specified
+argument can be specified
when the Value Node is created
to indicate the Node should already be considered
"built."
# $TARGET.
f = open(str(target[0]), 'wb')
f.write('prefix=' + source[0].get_contents())
-
+
# Fetch the prefix= argument, if any, from the command
# line, and use /usr/local as the default.
prefix = ARGUMENTS.get('prefix', '/usr/local')
.RI VariantDir( variant_dir ", " src_dir ", [" duplicate ])
.TP
.RI env.VariantDir( variant_dir ", " src_dir ", [" duplicate ])
-In effect, the
-.I src_dir
-directory tree is copied to
-.I variant_dir
-so a build can be performed there.
+Use the
+.BR VariantDir ()
+function to create a copy of your sources in another location:
+if a name under
+.IR variant_dir
+is not found but exists under
+.IR src_dir ,
+the file or directory is copied to
+.IR variant_dir .
+Target files can be built in a different directory than the original sources
+by simply refering to the sources (and targets) within the variant tree.
+
.BR VariantDir ()
can be called multiple times with the same
.I src_dir
to set up multiple builds with different options
.RI ( variants ).
+The
.I src_dir
-must be in or underneath the SConstruct file's directory, and
+location must be in or underneath the SConstruct file's directory, and
.I variant_dir
-may not be underneath the
-.I src_dir .
+may not be underneath
+.IR src_dir .
+'\"TODO: Can the above restrictions be clarified or relaxed?
+'\"TODO: The latter restriction is clearly not completely right;
+'\"TODO: src_dir = '.' works fine with a build dir under it.
The default behavior is for
.B scons
-to duplicate the source files in the variant tree
-and then build the derived files within the variant tree.
-This guarantees correct builds regardless of
-whether intermediate source files are generated during the build,
-whether preprocessors or other scanners search for included files
+to physically duplicate the source files in the variant tree.
+Thus, a build performed in the variant tree is guaranteed to be identical
+to a build performed in the source tree even if
+intermediate source files are generated during the build,
+or preprocessors or other scanners search for included files
relative to the source file,
-or whether individual compilers or other invoked tools are hard-coded
+or individual compilers or other invoked tools are hard-coded
to put derived files in the same directory as source files.
If possible on the platform,
files and directories that are not used are not present in
.IR variant_dir .
-Duplicating the source tree may be disabled by setting
+Duplicating the source tree may be disabled by setting the
.I duplicate
-to 0.
+argument to 0.
This will cause
.B scons
to invoke Builders using the path names of source files in
However, you would then call the subsidiary SConscript file
not in the source directory, but in the
.I variant_dir ,
-regardless of the value of
+regardless of the value of
.IR duplicate .
This is how you tell
.B scons
-which variant of a source tree to build.
-For example:
+which variant of a source tree to build:
.ES
-VariantDir('build-variant1', 'src')
-SConscript('build-variant1/SConscript')
-VariantDir('build-variant2', 'src')
-SConscript('build-variant2/SConscript')
+# run src/SConscript in two variant directories
+VariantDir('build/variant1', 'src')
+SConscript('build/variant1/SConscript')
+VariantDir('build/variant2', 'src')
+SConscript('build/variant2/SConscript')
.EE
.IP
for another way to specify a variant directory
in conjunction with calling a subsidiary SConscript file.
+Examples:
+
+.ES
+# use names in the build directory, not the source directory
+VariantDir('build', 'src', duplicate=0)
+Program('build/prog', 'build/source.c')
+.EE
+
+.ES
+# this variant builds both the source and docs
+VariantDir('build', '.', duplicate=0)
+SConscript(dirs=['build/src','build/doc'])
+.EE
+Or, equivalently:
+.ES
+SConscript(dirs=['build/src','build/doc'],
+ variant_dir = 'build', duplicate = 0)
+.EE
+
+.ES
+SConscript('build/SConscript', variant_dir = 'build', duplicate = 0)
+.EE
+Note that in the last example, the
+.I src_dir
+is not given, so the current directory is assumed, and the
+.B SConstruct
+and the
+.B SConscript
+are actually in the same directory, even though the
+.B SConscript
+is treated as if it were in the
+.B build
+subdirectory.
+
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
.RI WhereIs( program ", [" path ", " pathext ", " reject ])
.\" 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
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.LP
-Construction variables can be retrieved and set using the
-.B Dictionary
+Construction variables can be retrieved and set using the
+.B Dictionary
method of the construction environment:
.ES
env = Environment(CC="cc")
.EE
-or when copying a construction environment using the
-.B Clone
+or when copying a construction environment using the
+.B Clone
method:
.ES
.B scons
does not maintain an explicit cache of the tested values,
but uses its normal dependency tracking to keep the checked values
-up to date. However, users may override this behaviour with the
+up to date. However, users may override this behaviour with the
.B --config
command line option.
This environment may be modified when performing checks.
.I custom_tests
is a dictionary containing custom tests.
-See also the section about custom tests below.
+See also the section about custom tests below.
By default, no custom tests are added to the configure context.
.I conf_dir
specifies a directory where the test cases are built.
method,
you may want to specify a subdirectory under your variant directory.
.I config_h
-specifies a C header file where the results of tests
-will be written, e.g. #define HAVE_STDIO_H, #define HAVE_LIBM, etc.
+specifies a C header file where the results of tests
+will be written, e.g. #define HAVE_STDIO_H, #define HAVE_LIBM, etc.
The default is to not write a
.B config.h
file.
.B Configure
instance has the following associated methods:
-.TP
+.TP
.RI Configure.Finish( self )
This method should be called after configuration is done.
It returns the environment as modified
by the configuration checks performed.
After this method is called, no further checks can be performed
with this configuration context.
-However, you can create a new
-.RI Configure
+However, you can create a new
+.RI Configure
context to perform additional checks.
Only one context should be active at a time.
.TP
.RI Configure.CheckHeader( self ", " header ", [" include_quotes ", " language ])
-Checks if
+Checks if
.I header
is usable in the specified language.
.I header
.B #include
lines should precede the
header line being checked for.
-The optional argument
-.I include_quotes
+The optional argument
+.I include_quotes
must be
a two character string, where the first character denotes the opening
quote and the second character denotes the closing quote.
.RI Configure.CheckCHeader( self ", " header ", [" include_quotes ])
This is a wrapper around
.B Configure.CheckHeader
-which checks if
+which checks if
.I header
is usable in the C language.
.I header
.B #include
lines should precede the
header line being checked for.
-The optional argument
-.I include_quotes
+The optional argument
+.I include_quotes
must be
a two character string, where the first character denotes the opening
quote and the second character denotes the closing quote (both default
.RI Configure.CheckCXXHeader( self ", " header ", [" include_quotes ])
This is a wrapper around
.B Configure.CheckHeader
-which checks if
+which checks if
.I header
is usable in the C++ language.
.I header
.B #include
lines should precede the
header line being checked for.
-The optional argument
-.I include_quotes
+The optional argument
+.I include_quotes
must be
a two character string, where the first character denotes the opening
quote and the second character denotes the closing quote (both default
to \N'34').
-Returns 1 on success and 0 on failure.
+Returns 1 on success and 0 on failure.
.TP
.RI Configure.CheckFunc( self ", " function_name ", [" header ", " language ])
and selects the compiler to be used for the check;
the default is "C".
-.TP
+.TP
.RI Configure.CheckLib( self ", [" library ", " symbol ", " header ", " language ", " autoadd=1 ])
-Checks if
-.I library
-provides
+Checks if
+.I library
+provides
.IR symbol .
If the value of
.I autoadd
is 1 and the library provides the specified
.IR symbol ,
appends the library to the LIBS construction environment variable.
-.I library
+.I library
may also be None (the default),
-in which case
-.I symbol
+in which case
+.I symbol
is checked with the current LIBS variable,
or a list of library names,
in which case each library in the list
will be checked for
.IR symbol .
-If
+If
.I symbol
is not set or is
.BR None ,
is 1.
This method returns 1 on success and 0 on error.
-.TP
+.TP
.RI Configure.CheckLibWithHeader( self ", " library ", " header ", " language ", [" call ", " autoadd ])
-In contrast to the
-.RI Configure.CheckLib
+In contrast to the
+.RI Configure.CheckLib
call, this call provides a more sophisticated way to check against libraries.
-Again,
+Again,
.I library
-specifies the library or a list of libraries to check.
+specifies the library or a list of libraries to check.
.I header
specifies a header to check for.
.I header
can link against the specified
.IR library .
.I autoadd
-specifies whether to add the library to the environment (only if the check
+specifies whether to add the library to the environment (only if the check
succeeds). This method returns 1 on success and 0 on error.
.TP
if conf.CheckLibWithHeader( 'qt', 'qapp.h', 'c++', 'QApplication qapp(0,0);' ):
# do stuff for qt - usage, e.g.
conf.env.Append( CPPFLAGS = '-DWITH_QT' )
-env = conf.Finish()
+env = conf.Finish()
.EE
.TP
.EE
.EE
-You can define your own custom checks.
+You can define your own custom checks.
in addition to the predefined checks.
These are passed in a dictionary to the Configure function.
This dictionary maps the names of the checks
-to user defined Python callables
+to user defined Python callables
(either Python functions or class instances implementing the
.I __call__
method).
-The first argument of the call is always a
+The first argument of the call is always a
.I CheckContext
instance followed by the arguments,
which must be supplied by the user of the check.
These CheckContext instances define the following methods:
-.TP
+.TP
.RI CheckContext.Message( self ", " text )
-Usually called before the check is started.
+Usually called before the check is started.
.I text
will be displayed to the user, e.g. 'Checking for library X...'
.TP
.RI CheckContext.Result( self, ", " res )
-Usually called after the check is done.
+Usually called after the check is done.
.I res
-can be either an integer or a string. In the former case, 'ok' (res != 0)
-or 'failed' (res == 0) is displayed to the user, in the latter case the
+can be either an integer or a string. In the former case, 'ok' (res != 0)
+or 'failed' (res == 0) is displayed to the user, in the latter case the
given string is displayed.
.TP
.RI CheckContext.TryCompile( self ", " text ", " extension )
-Checks if a file with the specified
+Checks if a file with the specified
.I extension
-(e.g. '.c') containing
-.I text
+(e.g. '.c') containing
+.I text
can be compiled using the environment's
-.B Object
+.B Object
builder. Returns 1 on success and 0 on failure.
-.TP
+.TP
.RI CheckContext.TryLink( self ", " text ", " extension )
Checks, if a file with the specified
.I extension
-(e.g. '.c') containing
-.I text
+(e.g. '.c') containing
+.I text
can be compiled using the environment's
.B Program
builder. Returns 1 on success and 0 on failure.
.RI CheckContext.TryRun( self ", " text ", " extension )
Checks, if a file with the specified
.I extension
-(e.g. '.c') containing
-.I text
+(e.g. '.c') containing
+.I text
can be compiled using the environment's
.B Program
builder. On success, the program is run. If the program
.TP
.RI CheckContext.TryAction( self ", " action ", [" text ", " extension ])
Checks if the specified
-.I action
+.I action
with an optional source file (contents
.I text
-, extension
+, extension
.I extension
= ''
-) can be executed.
-.I action
-may be anything which can be converted to a
+) can be executed.
+.I action
+may be anything which can be converted to a
.B scons
.RI Action.
On success,
the methods above are based on this method.
Given the Builder instance
.I builder
-and the optional
+and the optional
.I text
of a source file with optional
.IR extension ,
-this method returns 1 on success and 0 on failure. In addition,
-.I self.lastTarget
+this method returns 1 on success and 0 on failure. In addition,
+.I self.lastTarget
is set to the build target node, if the build was successful.
.EE
context.env.Append(LIBS = 'qt', LIBPATH = qtdir + '/lib', CPPPATH = qtdir + '/include' )
ret = context.TryLink("""
#include <qapp.h>
-int main(int argc, char **argv) {
+int main(int argc, char **argv) {
QApplication qapp(argc, argv);
return 0;
}
if not conf.CheckQt('/usr/lib/qt'):
print 'We really need qt!'
Exit(1)
-env = conf.Finish()
+env = conf.Finish()
.EE
.SS Command-Line Construction Variables
some variables must be specified at build time.
For example, libraries needed for the build may be in non-standard
locations, or site-specific compiler options may need to be passed to the
-compiler.
+compiler.
.B scons
provides a
.B Variables
.TP
.RI Add( key ", [" help ", " default ", " validator ", " converter ])
-This adds a customizable construction variable to the Variables object.
+This adds a customizable construction variable to the Variables object.
.I key
-is the name of the variable.
-.I help
+is the name of the variable.
+.I help
is the help text for the variable.
-.I default
+.I default
is the default value of the variable;
if the default value is
.B None
.TP
.RI Save( filename ", " env )
-This saves the currently set variables into a script file named
+This saves the currently set variables into a script file named
.I filename
that can be used on the next invocation to automatically load the current
settings. This method combined with the Variables method can be used to
.TP
.RI GenerateHelpText( env ", [" sort ])
This generates help text documenting the customizable construction
-variables suitable to passing in to the Help() function.
+variables suitable to passing in to the Help() function.
.I env
is the construction environment that will be used to get the actual values
-of customizable variables. Calling with
+of customizable variables. Calling with
an optional
.I sort
function
to set up an option
whose value is a path name
of a package that may be
-enabled, disabled or
+enabled, disabled or
given an explicit path name.
The option will use
the specified name
.I File
or
.IR Dir .
-The
+The
.ES
# Get the current build dir's path, relative to top.
Builder objects are created
using the
-.B Builder
+.B Builder
function.
The
.B Builder
function accepts the following arguments:
.IP action
-The command line string used to build the target from the source.
+The command line string used to build the target from the source.
.B action
can also be:
a list of strings representing the command
An action function
takes three arguments:
-.I source
-- a list of source nodes,
+.I source
+- a list of source nodes,
.I target
- a list of target nodes,
.I env
- the construction environment.
-.IP prefix
+.IP prefix
The prefix that will be prepended to the target file name.
This may be specified as a:
.RS 10
.HP 6
-*
+*
.IR string ,
.HP 6
-*
+*
.I callable object
- a function or other callable that takes
two arguments (a construction environment and a list of sources)
and returns a prefix,
.HP 6
-*
+*
.I dictionary
-- specifies a mapping from a specific source suffix (of the first
+- specifies a mapping from a specific source suffix (of the first
source specified) to a corresponding target prefix. Both the source
suffix and target prefix specifications may use environment variable
substitution, and the target prefix (the 'value' entries in the
.EE
.IP ensure_suffix
-When set to any true value, causes
+When set to any true value, causes
.B scons
to add the target suffix specified by the
.I suffix
implicit dependencies
based only on the target file
and the construction environment,
-.I not
+.I not
for implicit
(See the section "Scanner Objects," below,
for information about creating Scanner objects.)
An emitter function
takes three arguments:
-.I source
-- a list of source nodes,
+.I source
+- a list of source nodes,
.I target
- a list of target nodes,
.I env
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 addition environment overrides, or associate a different
-builder with the target.
+builder with the target.
.IP env
A construction environment that can be used
The generator function
takes four arguments:
-.I source
-- a list of source nodes,
+.I source
+- a list of source nodes,
.I target
- a list of target nodes,
.I env
.ES
def g(source, target, env, for_signature):
- return [["gcc", "-c", "-o"] + target + source]
+ return [["gcc", "-c", "-o"] + target + source]
b = Builder(generator=g)
.EE
.IP
-The
+The
.I generator
and
.I action
.IP single_source
Specifies that this builder expects exactly one source file per call. Giving
more than one source files without target files results in implicitely calling
-the builder multiple times (once for each source given). Giving multiple
+the builder multiple times (once for each source given). Giving multiple
source files together with target files results in a UserError exception.
.RE
.IP
-The
+The
.I generator
and
.I action
the setting of
.B source_ext_match
prevents
-.B scons
+.B scons
from exiting with an error
due to the mismatched suffixes of
.B foo.in
will be set in the executing construction
environment when the Builder object is called.
The canonical example here would be
-to set a construction variable to
+to set a construction variable to
the repository of a source code system.
Any additional keyword arguments supplied
def build_it(target = None, source = None, env = None):
# build the target from the source
return 0
-
+
a = Action(build_it)
.EE
that arrange for various common
file and directory manipulations
to be performed.
-These are similar in concept to "tasks" in the
+These are similar in concept to "tasks" in the
Ant build tool,
although the implementation is slightly different.
These functions do not actually
without relying
on platform-specific
external commands:
-that
+that
.ES
env = Environment(TMPBUILD = '/tmp/builddir')
env.Command('foo.out', 'foo.in',
variables for each command execution:
.IP TARGET
-The file name of the target being built, or the file name of the first
+The file name of the target being built, or the file name of the first
target if multiple targets are being built.
.IP TARGETS
(Note that the above variables are reserved
and may not be set in a construction environment.)
-.LP
+.LP
For example, given the construction variable CC='cc', targets=['foo'], and
sources=['foo.c', 'bar.c']:
take four arguments:
.I target
- a list of target nodes,
-.I source
-- a list of source nodes,
+.I source
+- a list of source nodes,
.I env
- the construction environment,
.I for_signature
.IP String
When the value is a string it is interpreted as a space delimited list of
-command line arguments.
+command line arguments.
.IP List
When the value is a list it is interpreted as a list of command line
for the different file types that this
Scanner knows how to scan.
If the argument is a string,
-then it will be expanded
+then it will be expanded
into a list by the current environment.
.IP path_function
the
.BR Object (),
.BR SharedObject (),
-and
+and
.BR StaticObject ()
builders to decide
which scanner should be used
the underlying system.
On a case-sensitive system
such as Linux or UNIX,
-SCons treats a file with a
+SCons treats a file with a
.B .C
suffix as a C++ source file.
On a case-insensitive system
such as Windows,
-SCons treats a file with a
+SCons treats a file with a
.B .C
suffix as a C source file.
.SS .F file suffix
the underlying system.
On a case-sensitive system
such as Linux or UNIX,
-SCons treats a file with a
+SCons treats a file with a
.B .F
suffix as a Fortran source file
that is to be first run through
the standard C preprocessor.
On a case-insensitive system
such as Windows,
-SCons treats a file with a
+SCons treats a file with a
.B .F
suffix as a Fortran source file that should
.I not
tools, if they are both installed, regardless of the order of the bin
directories in the PATH variable. If you have both MSVC and MinGW
installed and you want to use MinGW instead of MSVC,
-then you must explictly tell SCons to use MinGW by passing
+then you must explictly tell SCons to use MinGW by passing
.ES
tools=['mingw']
for inc in includes:
for dir in path:
file = dir + os.sep + inc
- if os.path.exists(file):
+ if os.path.exists(file):
results.append(file)
break
return results
Import('env')
env.Library('a', Split('a1.c a2.c a3.c'))
-libB/SConscript:
+libB/SConscript:
Import('env')
env.Library('b', Split('b1.c b2.c b3.c'))
allows SCons to append the appropriate library
prefix and suffix for the current platform
(for example, 'liba.a' on POSIX systems,
-'a.lib' on Windows).
+\&'a.lib' on Windows).
.SS Customizing construction variables from the command line.
The following would allow the C compiler to be specified on the command
-line or in the file custom.py.
+line or in the file custom.py.
.ES
vars = Variables('custom.py')
cause their size to increase significantly, Microsoft provides a mechanism
for including the debugging information in an external file called a PDB
file. SCons supports PDB files through the PDB construction
-variable.
+variable.
SConstruct:
.ES
-->
<!ENTITY Add "<function>Add</function>">
+<!ENTITY AddMethod "<function>AddMethod</function>">
<!ENTITY AddPostAction "<function>AddPostAction</function>">
<!ENTITY AddPreAction "<function>AddPreAction</function>">
+<!ENTITY AddOption "<function>AddOption</function>">
<!ENTITY AddOptions "<function>AddOptions</function>">
<!ENTITY AddVariables "<function>AddVariables</function>">
<!ENTITY Alias "<function>Alias</function>">
<!ENTITY Copy "<function>Copy</function>">
<!ENTITY Decider "<function>Decider</function>">
<!ENTITY Default "<function>Default</function>">
+<!ENTITY DefaultEnvironment "<function>DefaultEnvironment</function>">
<!ENTITY DefaultRules "<function>DefaultRules</function>">
<!ENTITY Delete "<function>Delete</function>">
<!ENTITY Depends "<function>Depends</function>">
<!ENTITY Entry "<function>Entry</function>">
<!ENTITY EnumOption "<function>EnumOption</function>">
<!ENTITY EnumVariable "<function>EnumVariable</function>">
+<!ENTITY EnsurePythonVersion "<function>EnsurePythonVersion</function>">
+<!ENTITY EnsureSConsVersion "<function>EnsureSConsVersion</function>">
<!ENTITY Environment "<function>Environment</function>">
<!ENTITY Execute "<function>Execute</function>">
+<!ENTITY Exit "<function>Exit</function>">
<!ENTITY Export "<function>Export</function>">
<!ENTITY File "<function>File</function>">
<!ENTITY FindFile "<function>FindFile</function>">
<!ENTITY FindInstalledFiles "<function>FindInstalledFiles</function>">
<!ENTITY Finish "<function>Finish</function>">
+<!ENTITY Flatten "<function>Flatten</function>">
<!ENTITY GenerateHelpText "<function>GenerateHelpText</function>">
+<!ENTITY GetBuildFailures "<function>GetBuildFailures</function>">
<!ENTITY GetOption "<function>GetOption</function>">
+<!ENTITY Glob "<function>Glob</function>">
<!ENTITY Help "<function>Help</function>">
<!ENTITY Ignore "<function>Ignore</function>">
<!ENTITY Import "<function>Import</function>">
<!ENTITY ListOption "<function>ListOption</function>">
<!ENTITY ListVariable "<function>ListVariable</function>">
<!ENTITY Local "<function>Local</function>">
+<!ENTITY MergeFlags "<function>MergeFlags</function>">
<!ENTITY Mkdir "<function>Mkdir</function>">
<!ENTITY Module "<function>Module</function>">
<!ENTITY Move "<function>Move</function>">
<!ENTITY PackageOption "<function>PackageOption</function>">
<!ENTITY PackageVariable "<function>PackageVariable</function>">
<!ENTITY ParseConfig "<function>ParseConfig</function>">
+<!ENTITY ParseFlags "<function>ParseFlags</function>">
<!ENTITY PathOption "<function>PathOption</function>">
<!ENTITY PathOption_PathAccept "<function>PathOption.PathAccept</function>">
<!ENTITY PathOption_PathExists "<function>PathOption.PathExists</function>">
<!ENTITY Prepend "<function>Prepend</function>">
<!ENTITY PrependENVPath "<function>PrependENVPath</function>">
<!ENTITY PrependUnique "<function>PrependUnique</function>">
+<!ENTITY Progress "<function>Progress</function>">
<!ENTITY Replace "<function>Replace</function>">
<!ENTITY Repository "<function>Repository</function>">
+<!ENTITY Requires "<function>Requires</function>">
<!ENTITY Return "<function>Return</function>">
<!ENTITY RuleSet "<function>RuleSet</function>">
<!ENTITY Salt "<function>Salt</function>">
<!ENTITY SetBuildSignatureType "<function>SetBuildSignatureType</function>">
<!ENTITY SetContentSignatureType "<function>SetContentSignatureType</function>">
+<!ENTITY SetDefault "<function>SetDefault</function>">
<!ENTITY SetOption "<function>SetOption</function>">
<!ENTITY SideEffect "<function>SideEffect</function>">
<!ENTITY SourceSignature "<function>SourceSignature</function>">
<!ENTITY TargetSignatures "<function>TargetSignatures</function>">
<!ENTITY Task "<function>Task</function>">
<!ENTITY Touch "<function>Touch</function>">
+<!ENTITY UnknownOptions "<function>UnknownOptions</function>">
+<!ENTITY UnknownVariables "<function>UnknownVariables</function>">
<!-- Environment methods -->
<!ENTITY subst "<function>subst</function>">
-->
+<!ENTITY ARGLIST "<varname>ARGLIST</varname>">
<!ENTITY ARGUMENTS "<varname>ARGUMENTS</varname>">
<!ENTITY BUILD_TARGETS "<varname>BUILD_TARGETS</varname>">
<!ENTITY COMMAND_LINE_TARGETS "<varname>COMMAND_LINE_TARGETS</varname>">
<!ENTITY COLOR "<varname>COLOR</varname>">
<!ENTITY COLORS "<varname>COLORS</varname>">
<!ENTITY CONFIG "<varname>CONFIG</varname>">
+<!ENTITY CPPDEFINES "<varname>CPPDEFINES</varname>">
<!ENTITY RELEASE "<varname>RELEASE</varname>">
<!ENTITY RELEASE_BUILD "<varname>RELEASE_BUILD</varname>">
<!ENTITY SCANNERMAP "<varname>SCANNERMAP</varname>">
<!ENTITY exports "<varname>exports</varname>">
<!ENTITY source "<varname>source</varname>">
<!ENTITY target "<varname>target</varname>">
+<!ENTITY variables "<varname>variables</varname>">
<!ENTITY variant_dir "<varname>variant_dir</varname>">
+++ /dev/null
-
-<!--
-
- __COPYRIGHT__
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
- KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
--->
-
- <para>
-
- When &SCons; builds a target file,
- it does not execute the commands with
- the same external environment
- that you used to execute &SCons;.
- Instead, it uses the dictionary
- stored in the &cv-link-ENV; construction variable
- as the external environment
- for executing commands.
-
- </para>
-
- <para>
-
- The most important ramification of this behavior
- is that the &PATH; environment variable,
- which controls where the operating system
- will look for commands and utilities,
- is not the same as in the external environment
- from which you called &SCons;.
- This means that &SCons; will not, by default,
- necessarily find all of the tools
- that you can execute from the command line.
-
- </para>
-
- <para>
-
- The default value of the &PATH; environment variable
- on a POSIX system
- is <literal>/usr/local/bin:/bin:/usr/bin</literal>.
- The default value of the &PATH; environment variable
- on a Windows system comes from the Windows registry
- value for the command interpreter.
- If you want to execute any commands--compilers, linkers, etc.--that
- are not in these default locations,
- you need to set the &PATH; value
- in the &cv-ENV; dictionary
- in your construction environment.
-
- </para>
-
- <para>
-
- The simplest way to do this is to initialize explicitly
- the value when you create the construction environment;
- this is one way to do that:
-
- </para>
-
- <sconstruct>
- path = ['/usr/local/bin', '/bin', '/usr/bin']
- env = Environment(ENV = {'PATH' : path})
- </sconstruct>
-
- <para>
-
- Assign a dictionary to the &cv-ENV;
- construction variable in this way
- completely resets the external environment
- so that the only variable that will be
- set when external commands are executed
- will be the &PATH; value.
- If you want to use the rest of
- the values in &cv-ENV; and only
- set the value of &PATH;,
- the most straightforward way is probably:
-
- </para>
-
- <sconstruct>
- env['ENV']['PATH'] = ['/usr/local/bin', '/bin', '/usr/bin']
- </sconstruct>
-
- <para>
-
- Note that &SCons; does allow you to define
- the directories in the &PATH; in a string,
- separated by the pathname-separator character
- for your system (':' on POSIX systems, ';' on Windows):
-
- </para>
-
- <sconstruct>
- env['ENV']['PATH'] = '/usr/local/bin:/bin:/usr/bin'
- </sconstruct>
-
- <para>
-
- But doing so makes your &SConscript; file less portable,
- (although in this case that may not be a huge concern
- since the directories you list are likley system-specific, anyway).
-
- </para>
-
- <!--
-
- <scons_example name="ex1">
- <file name="SConstruct" printme="1">
- env = Environment()
- env.Command('foo', [], '__ROOT__/usr/bin/printenv.py')
- </file>
- <file name="__ROOT__/usr/bin/printenv.py" chmod="0755">
- #!/usr/bin/env python
- import os
- import sys
- if len(sys.argv) > 1:
- keys = sys.argv[1:]
- else:
- keys = os.environ.keys()
- keys.sort()
- for key in keys:
- print " " + key + "=" + os.environ[key]
- </file>
- </scons_example>
-
- <para>
-
- </para>
-
- <scons_output example="ex1">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
-
- -->
-
- <section>
- <title>Propagating &PATH; From the External Environment</title>
-
- <para>
-
- You may want to propagate the external &PATH;
- to the execution environment for commands.
- You do this by initializing the &PATH;
- variable with the &PATH; value from
- the <literal>os.environ</literal>
- dictionary,
- which is Python's way of letting you
- get at the external environment:
-
- </para>
-
- <sconstruct>
- import os
- env = Environment(ENV = {'PATH' : os.environ['PATH']})
- </sconstruct>
-
- <para>
-
- Alternatively, you may find it easier
- to just propagate the entire external
- environment to the execution environment
- for commands.
- This is simpler to code than explicity
- selecting the &PATH; value:
-
- </para>
-
- <sconstruct>
- import os
- env = Environment(ENV = os.environ)
- </sconstruct>
-
- <para>
-
- Either of these will guarantee that
- &SCons; will be able to execute
- any command that you can execute from the command line.
- The drawback is that the build can behave
- differently if it's run by people with
- different &PATH; values in their environment--for example,
- if both the <literal>/bin</literal> and
- <literal>/usr/local/bin</literal> directories
- have different &cc; commands,
- then which one will be used to compile programs
- will depend on which directory is listed
- first in the user's &PATH; variable.
-
- </para>
-
- </section>
+++ /dev/null
-
-<!--
-
- __COPYRIGHT__
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
- KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
--->
-
- <para>
-
- When &SCons; builds a target file,
- it does not execute the commands with
- the same external environment
- that you used to execute &SCons;.
- Instead, it uses the dictionary
- stored in the &cv-link-ENV; construction variable
- as the external environment
- for executing commands.
-
- </para>
-
- <para>
-
- The most important ramification of this behavior
- is that the &PATH; environment variable,
- which controls where the operating system
- will look for commands and utilities,
- is not the same as in the external environment
- from which you called &SCons;.
- This means that &SCons; will not, by default,
- necessarily find all of the tools
- that you can execute from the command line.
-
- </para>
-
- <para>
-
- The default value of the &PATH; environment variable
- on a POSIX system
- is <literal>/usr/local/bin:/bin:/usr/bin</literal>.
- The default value of the &PATH; environment variable
- on a Windows system comes from the Windows registry
- value for the command interpreter.
- If you want to execute any commands--compilers, linkers, etc.--that
- are not in these default locations,
- you need to set the &PATH; value
- in the &cv-ENV; dictionary
- in your construction environment.
-
- </para>
-
- <para>
-
- The simplest way to do this is to initialize explicitly
- the value when you create the construction environment;
- this is one way to do that:
-
- </para>
-
- <programlisting>
- path = ['/usr/local/bin', '/bin', '/usr/bin']
- env = Environment(ENV = {'PATH' : path})
- </programlisting>
-
- <para>
-
- Assign a dictionary to the &cv-ENV;
- construction variable in this way
- completely resets the external environment
- so that the only variable that will be
- set when external commands are executed
- will be the &PATH; value.
- If you want to use the rest of
- the values in &cv-ENV; and only
- set the value of &PATH;,
- the most straightforward way is probably:
-
- </para>
-
- <programlisting>
- env['ENV']['PATH'] = ['/usr/local/bin', '/bin', '/usr/bin']
- </programlisting>
-
- <para>
-
- Note that &SCons; does allow you to define
- the directories in the &PATH; in a string,
- separated by the pathname-separator character
- for your system (':' on POSIX systems, ';' on Windows):
-
- </para>
-
- <programlisting>
- env['ENV']['PATH'] = '/usr/local/bin:/bin:/usr/bin'
- </programlisting>
-
- <para>
-
- But doing so makes your &SConscript; file less portable,
- (although in this case that may not be a huge concern
- since the directories you list are likley system-specific, anyway).
-
- </para>
-
- <!--
-
- <scons_example name="ex1">
- <file name="SConstruct" printme="1">
- env = Environment()
- env.Command('foo', [], '__ROOT__/usr/bin/printenv.py')
- </file>
- <file name="__ROOT__/usr/bin/printenv.py" chmod="0755">
- #!/usr/bin/env python
- import os
- import sys
- if len(sys.argv) > 1:
- keys = sys.argv[1:]
- else:
- keys = os.environ.keys()
- keys.sort()
- for key in keys:
- print " " + key + "=" + os.environ[key]
- </file>
- </scons_example>
-
- <para>
-
- </para>
-
- <scons_output example="ex1">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
-
- -->
-
- <section>
- <title>Propagating &PATH; From the External Environment</title>
-
- <para>
-
- You may want to propagate the external &PATH;
- to the execution environment for commands.
- You do this by initializing the &PATH;
- variable with the &PATH; value from
- the <literal>os.environ</literal>
- dictionary,
- which is Python's way of letting you
- get at the external environment:
-
- </para>
-
- <programlisting>
- import os
- env = Environment(ENV = {'PATH' : os.environ['PATH']})
- </programlisting>
-
- <para>
-
- Alternatively, you may find it easier
- to just propagate the entire external
- environment to the execution environment
- for commands.
- This is simpler to code than explicity
- selecting the &PATH; value:
-
- </para>
-
- <programlisting>
- import os
- env = Environment(ENV = os.environ)
- </programlisting>
-
- <para>
-
- Either of these will guarantee that
- &SCons; will be able to execute
- any command that you can execute from the command line.
- The drawback is that the build can behave
- differently if it's run by people with
- different &PATH; values in their environment--for example,
- if both the <literal>/bin</literal> and
- <literal>/usr/local/bin</literal> directories
- have different &cc; commands,
- then which one will be used to compile programs
- will depend on which directory is listed
- first in the user's &PATH; variable.
-
- </para>
-
- </section>
cons.pl
copyright.xml
depends.xml
-ENV.xml
environments.xml
errors.xml
example.xml
factories.xml
file-removal.xml
-help.xml
hierarchy.xml
install.xml
java.xml
less-simple.xml
main.xml
make.xml
+mergeflags.xml
+misc.xml
nodes.xml
+output.xml
parseconfig.xml
+parseflags.xml
preface.xml
python.xml
repositories.xml
To build the .xml files from the .in files:
scons -D . BUILDDOC=1
+To build the whole PDF doc from this dir, for testing:
+ scons -D ../../build/doc/PDF/scons-user.pdf
Writing examples: here's a simple template.
<para>
- The env.AddMethod(function, [name]) function is used to add a method
- to an environment. It's typically used to add a "pseudo-builder" or
- wrap up a call to multiple builders. In the first example, we want
- to install the program into the standard bin dir, but also copy it
- into a local install/bin dir that might be used to build a package
- from.
+ The &AddMethod; function is used to add a method
+ to an environment. It's typically used to add a "pseudo-builder,"
+ a function that looks like a &Builder; but
+ wraps up calls to multiple other &Builder;s
+ or otherwise processes its arguments
+ before calling one or more &Builder;s.
+ In the following example,
+ we want to install the program into the standard
+ <filename>/usr/bin</filename> directory hierarchy,
+ but also copy it into a local <filename>install/bin</filename>
+ directory from which a package might be built:
</para>
"""Install source in both bin dirs"""
i1 = env.Install("$BIN", source)
i2 = env.Install("$LOCALBIN", source)
- return [i1[0], i2][0] # Return a list, like a normal builder
- env = Environment(BIN='/usr/bin', LOCALBIN='#install/bin')
+ return [i1[0], i2[0]] # Return a list, like a normal builder
+ env = Environment(BIN='__ROOT__/usr/bin', LOCALBIN='#install/bin')
env.AddMethod(install_in_bin_dirs, "InstallInBinDirs")
env.InstallInBinDirs(Program('hello.c')) # installs hello in both bin dirs
</file>
<para>
- It also gives more flexibility in parsing arguments than you can get
- with a builder. The next example shows a pseudo-builder with a
+ As mentioned, a psuedo-builder also provides more flexibility
+ in parsing arguments than you can get with a &Builder;.
+ The next example shows a pseudo-builder with a
named argument that modifies the filename, and a separate argument
for the resource file (rather than having the builder figure it out
- by file extension). Also this example demonstrates using the global
- AddMethod function to add a method to the global Environment class,
+ by file extension). This example also demonstrates using the global
+ &AddMethod; function to add a method to the global Environment class,
so it will be used in all subsequently created environments.
</para>
<scons_example name="ex2">
<file name="SConstruct" printme="1">
- import sys
def BuildTestProg(env, testfile, resourcefile, testdir="tests"):
"""Build the test program;
- prepends "test_" to src and target, and puts target into testdir."""
- srcfile="test_%s.c"%testfile
- if sys.platform=='win32':
- target="%s/test_%s$EXESUFFIX"%(testdir,[testfile, resourcefile])
+ prepends "test_" to src and target,
+ and puts target into testdir."""
+ srcfile = "test_%s.c" % testfile
+ target = "%s/test_%s" % (testdir, testfile)
+ if env['PLATFORM'] == 'win32':
+ resfile = env.RES(resourcefile)
+ p = env.Program(target, [srcfile, resfile])
else:
- target="%s/test_%s$EXESUFFIX"%(testdir,testfile)
- p = env.Program(target, srcfile)
+ p = env.Program(target, srcfile)
return p
AddMethod(Environment, BuildTestProg)
- # Now use it
- env=Environment()
+ env = Environment()
env.BuildTestProg('stuff', resourcefile='res.rc')
</file>
<file name="test_stuff.c">
int main() { printf("Hello, world!\n"); }
</file>
+ <file name="res.rc">
+ res.rc
+ </file>
</scons_example>
<para>
- This produces the following (on Linux, anyway; Windows would include the
- resource file):
+ This produces the following on Linux:
</para>
<scons_output example="ex2">
</scons_output>
<para>
- Using AddMethod is better than just adding an instance method to an
- Environment because it gets called as a proper method, and AddMethod
- provides for copying the method to any copies of the Environment
- instance.
+ And the following on Windows:
+ </para>
+
+ <scons_output example="ex2" os="win32">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+ Using &AddMethod; is better than just adding an instance method
+ to a &consenv; because it gets called as a proper method,
+ and because &AddMethod; provides for copying the method
+ to any clones of the &consenv; instance.
</para>
<para>
- The env.AddMethod(function, [name]) function is used to add a method
- to an environment. It's typically used to add a "pseudo-builder" or
- wrap up a call to multiple builders. In the first example, we want
- to install the program into the standard bin dir, but also copy it
- into a local install/bin dir that might be used to build a package
- from.
+ The &AddMethod; function is used to add a method
+ to an environment. It's typically used to add a "pseudo-builder,"
+ a function that looks like a &Builder; but
+ wraps up calls to multiple other &Builder;s
+ or otherwise processes its arguments
+ before calling one or more &Builder;s.
+ In the following example,
+ we want to install the program into the standard
+ <filename>/usr/bin</filename> directory hierarchy,
+ but also copy it into a local <filename>install/bin</filename>
+ directory from which a package might be built:
</para>
"""Install source in both bin dirs"""
i1 = env.Install("$BIN", source)
i2 = env.Install("$LOCALBIN", source)
- return [i1[0], i2][0] # Return a list, like a normal builder
+ return [i1[0], i2[0]] # Return a list, like a normal builder
env = Environment(BIN='/usr/bin', LOCALBIN='#install/bin')
env.AddMethod(install_in_bin_dirs, "InstallInBinDirs")
env.InstallInBinDirs(Program('hello.c')) # installs hello in both bin dirs
% <userinput>scons -Q /</userinput>
cc -o hello.o -c hello.c
cc -o hello hello.o
- Install file: "hello" as "install/bin/hello"
Install file: "hello" as "/usr/bin/hello"
+ Install file: "hello" as "install/bin/hello"
</screen>
<para>
- It also gives more flexibility in parsing arguments than you can get
- with a builder. The next example shows a pseudo-builder with a
+ As mentioned, a psuedo-builder also provides more flexibility
+ in parsing arguments than you can get with a &Builder;.
+ The next example shows a pseudo-builder with a
named argument that modifies the filename, and a separate argument
for the resource file (rather than having the builder figure it out
- by file extension). Also this example demonstrates using the global
- AddMethod function to add a method to the global Environment class,
+ by file extension). This example also demonstrates using the global
+ &AddMethod; function to add a method to the global Environment class,
so it will be used in all subsequently created environments.
</para>
<programlisting>
- import sys
def BuildTestProg(env, testfile, resourcefile, testdir="tests"):
"""Build the test program;
- prepends "test_" to src and target, and puts target into testdir."""
- srcfile="test_%s.c"%testfile
- if sys.platform=='win32':
- target="%s/test_%s$EXESUFFIX"%(testdir,[testfile, resourcefile])
+ prepends "test_" to src and target,
+ and puts target into testdir."""
+ srcfile = "test_%s.c" % testfile
+ target = "%s/test_%s" % (testdir, testfile)
+ if env['PLATFORM'] == 'win32':
+ resfile = env.RES(resourcefile)
+ p = env.Program(target, [srcfile, resfile])
else:
- target="%s/test_%s$EXESUFFIX"%(testdir,testfile)
- p = env.Program(target, srcfile)
+ p = env.Program(target, srcfile)
return p
AddMethod(Environment, BuildTestProg)
- # Now use it
- env=Environment()
+ env = Environment()
env.BuildTestProg('stuff', resourcefile='res.rc')
</programlisting>
<para>
- This produces the following (on Linux, anyway; Windows would include the
- resource file):
+ This produces the following on Linux:
</para>
<screen>
</screen>
<para>
- Using AddMethod is better than just adding an instance method to an
- Environment because it gets called as a proper method, and AddMethod
- provides for copying the method to any copies of the Environment
- instance.
+ And the following on Windows:
+ </para>
+
+ <screen>
+ C:\><userinput>scons -Q</userinput>
+ rc /fores.res res.rc
+ cl /nologo /c test_stuff.c /Fotest_stuff.obj
+ link /nologo /OUT:tests\test_stuff.exe test_stuff.obj res.res
+ </screen>
+
+ <para>
+ Using &AddMethod; is better than just adding an instance method
+ to a &consenv; because it gets called as a proper method,
+ and because &AddMethod; provides for copying the method
+ to any clones of the &consenv; instance.
</para>
Because &SCons; is written in Python,
you must obviously have Python installed on your system
- to use &SCons;
+ to use &SCons;.
Before you try to install Python,
you should check to see if Python is already
available on your system by typing
- <userinput>python</userinput>
+ <userinput>python -V</userinput>
+ (capital 'V')
+ or
+ <userinput>python --version</userinput>
at your system's command-line prompt.
- You should see something like the following
- on a UNIX or Linux system that has Python installed:
</para>
- <!--
- Robert P.J. Day has suggested using "python -V",
- but that's not supported in 1.5.2, so we're going
- to leave this as is for now.
- -->
-
<screen>
- $ <userinput>python</userinput>
- Python 2.2.2 (#1, Feb 24 2003, 19:13:11)
- [GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-4)] on linux2
- Type "help", "copyright", "credits" or "license" for more information.
- >>> <userinput>^D</userinput>
+ $ <userinput>python -V</userinput>
+ Python 2.5.1
</screen>
<para>
</para>
<screen>
- C:\><userinput>python</userinput>
- Python 2.2.2 (#34, Apr 9 2002, 19:34:33) [MSC 32 bit (Intel)] on win32
- Type "help", "copyright", "credits" or "license" for more information.
- >>> <userinput>^Z</userinput>
+ C:\><userinput>python -V</userinput>
+ Python 2.5.1
</screen>
<para>
- The <prompt>>>></prompt> is the input prompt
- for the Python interpreter.
- The <userinput>^D</userinput> and <userinput>^Z</userinput>
- represent the CTRL-D and CTRL-Z characters
- that you will need to type to get out of the interpreter
- before proceeding to installing &SCons;.
-
- </para>
-
- <para>
-
If Python is not installed on your system,
you will see an error message
stating something like "command not found"
<para>
+ (Note that the <option>-V</option> option
+ was added to Python version 2.0,
+ so if your system only has an earlier version available
+ you may see an
+ <literal>"Unknown option: -V"</literal>
+ error message.)
+
+ </para>
+
+ <para>
+
The standard location for information
about downloading and installing Python is
<ulink url="http://www.python.org/download/">http://www.python.org/download/</ulink>.
</para>
+ <para>
+
+ &SCons; will work with any version of Python from 1.5.2 or later.
+ If you need to install Python and have a choice,
+ we recommend using the most recent Python 2.5 version available.
+ Python 2.5 has significant improvements
+ the help speed up the performance of &SCons;'.
+
+ </para>
+
</section>
<section>
install the <application>scons</application> script
in the default system scripts directory
(<filename>/usr/local/bin</filename> or
- <filename>C:\Python2.2\Scripts</filename>),
+ <filename>C:\Python25\Scripts</filename>),
and will install the &SCons; build engine
in an appropriate stand-alone library directory
(<filename>/usr/local/lib/scons</filename> or
- <filename>C:\Python2.2\scons</filename>).
+ <filename>C:\Python25\scons</filename>).
Because these are system directories,
you may need root (on Linux or UNIX) or Administrator (on Windows)
privileges to install &SCons; like this.
in the
<filename>/usr/lib/scons-__VERSION__</filename>
or
- <filename>C:\Python2.2\scons-__VERSION__</filename>
+ <filename>C:\Python25\scons-__VERSION__</filename>
directory, for example.
</para>
Because &SCons; is written in Python,
you must obviously have Python installed on your system
- to use &SCons;
+ to use &SCons;.
Before you try to install Python,
you should check to see if Python is already
available on your system by typing
- <userinput>python</userinput>
+ <userinput>python -V</userinput>
+ (capital 'V')
+ or
+ <userinput>python --version</userinput>
at your system's command-line prompt.
- You should see something like the following
- on a UNIX or Linux system that has Python installed:
</para>
- <!--
- Robert P.J. Day has suggested using "python -V",
- but that's not supported in 1.5.2, so we're going
- to leave this as is for now.
- -->
-
<screen>
- $ <userinput>python</userinput>
- Python 2.2.2 (#1, Feb 24 2003, 19:13:11)
- [GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-4)] on linux2
- Type "help", "copyright", "credits" or "license" for more information.
- >>> <userinput>^D</userinput>
+ $ <userinput>python -V</userinput>
+ Python 2.5.1
</screen>
<para>
</para>
<screen>
- C:\><userinput>python</userinput>
- Python 2.2.2 (#34, Apr 9 2002, 19:34:33) [MSC 32 bit (Intel)] on win32
- Type "help", "copyright", "credits" or "license" for more information.
- >>> <userinput>^Z</userinput>
+ C:\><userinput>python -V</userinput>
+ Python 2.5.1
</screen>
<para>
- The <prompt>>>></prompt> is the input prompt
- for the Python interpreter.
- The <userinput>^D</userinput> and <userinput>^Z</userinput>
- represent the CTRL-D and CTRL-Z characters
- that you will need to type to get out of the interpreter
- before proceeding to installing &SCons;.
-
- </para>
-
- <para>
-
If Python is not installed on your system,
you will see an error message
stating something like "command not found"
<para>
+ (Note that the <option>-V</option> option
+ was added to Python version 2.0,
+ so if your system only has an earlier version available
+ you may see an
+ <literal>"Unknown option: -V"</literal>
+ error message.)
+
+ </para>
+
+ <para>
+
The standard location for information
about downloading and installing Python is
<ulink url="http://www.python.org/download/">http://www.python.org/download/</ulink>.
</para>
+ <para>
+
+ &SCons; will work with any version of Python from 1.5.2 or later.
+ If you need to install Python and have a choice,
+ we recommend using the most recent Python 2.5 version available.
+ Python 2.5 has significant improvements
+ the help speed up the performance of &SCons;'.
+
+ </para>
+
</section>
<section>
install the <application>scons</application> script
in the default system scripts directory
(<filename>/usr/local/bin</filename> or
- <filename>C:\Python2.2\Scripts</filename>),
+ <filename>C:\Python25\Scripts</filename>),
and will install the &SCons; build engine
in an appropriate stand-alone library directory
(<filename>/usr/local/lib/scons</filename> or
- <filename>C:\Python2.2\scons</filename>).
+ <filename>C:\Python25\scons</filename>).
Because these are system directories,
you may need root (on Linux or UNIX) or Administrator (on Windows)
privileges to install &SCons; like this.
in the
<filename>/usr/lib/scons-__VERSION__</filename>
or
- <filename>C:\Python2.2\scons-__VERSION__</filename>
+ <filename>C:\Python25\scons-__VERSION__</filename>
directory, for example.
</para>
&SCons; supports the ability for a Builder to modify the
lists of target(s) from the specified source(s).
+ You do this by defining an &emitter; function
+ that takes as its arguments
+ the list of the targets passed to the builder,
+ the list of the sources passed to the builder,
+ and the construction environment.
+ The emitter function should return the modified
+ lists of targets that should be built
+ and sources from which the targets will be built.
+
+ </para>
+
+ <para>
+
+ For example, suppose you want to define a Builder
+ that always calls a <filename>foobuild</filename> program,
+ and you want to automatically add
+ a new target file named
+ <filename>new_target</filename>
+ and a new source file named
+ <filename>new_source</filename>
+ whenever it's called.
+ The &SConstruct; file might look like this:
</para>
env.Foo('file')
</sconstruct>
+ <para>
+
+ And would yield the following output:
+
+ </para>
+
<scons_output example="ex7">
<scons_output_command>scons -Q</scons_output_command>
</scons_output>
- <programlisting>
- bld = Builder(action = 'my_command',
- suffix = '.foo',
- src_suffix = '.input',
- emitter = 'MY_EMITTER')
- def modify1(target, source, env):
- return target, source
- def modify2(target, source, env):
- return target, source
- env1 = Environment(BUILDERS = {'Foo' : bld},
- MY_EMITTER = modify1)
- env2 = Environment(BUILDERS = {'Foo' : bld},
- MY_EMITTER = modify2)
- env1.Foo('file1')
- env2.Foo('file2')
- </programlisting>
+ <para>
+
+ One very flexible thing that you can is specify
+ use a construction variable to specify
+ different emitter functions for different
+ construction variable.
+ To do this, specify a string
+ containing a construction variable
+ expansion as the emitter when you call
+ the &Builder; function,
+ and set that construction variable to
+ the desired emitter function
+ in different construction environments:
+
+ </para>
+
+ <scons_example name="MY_EMITTER">
+
+ <file name="SConstruct" printme="1">
+ bld = Builder(action = 'my_command $SOURCES > $TARGET',
+ suffix = '.foo',
+ src_suffix = '.input',
+ emitter = '$MY_EMITTER')
+ def modify1(target, source, env):
+ return target, source + ['modify1.in']
+ def modify2(target, source, env):
+ return target, source + ['modify2.in']
+ env1 = Environment(BUILDERS = {'Foo' : bld},
+ MY_EMITTER = modify1)
+ env2 = Environment(BUILDERS = {'Foo' : bld},
+ MY_EMITTER = modify2)
+ env1.Foo('file1')
+ env2.Foo('file2')
+ import os
+ env1['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd()
+ env2['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd()
+ </file>
+ <file name="file1.input">
+ file1.input
+ </file>
+ <file name="file2.input">
+ file2.input
+ </file>
+ <file name="modify1.in">
+ modify1.input
+ </file>
+ <file name="modify2.in">
+ modify2.input
+ </file>
+ <file name="my_command" chmod="0755">
+ cat
+ </file>
+ </file>
+
+ </scons_example>
+
+ <sconstruct>
+ bld = Builder(action = 'my_command $SOURCES > $TARGET',
+ suffix = '.foo',
+ src_suffix = '.input',
+ emitter = '$MY_EMITTER')
+ def modify1(target, source, env):
+ return target, source + ['modify1.in']
+ def modify2(target, source, env):
+ return target, source + ['modify2.in']
+ env1 = Environment(BUILDERS = {'Foo' : bld},
+ MY_EMITTER = modify1)
+ env2 = Environment(BUILDERS = {'Foo' : bld},
+ MY_EMITTER = modify2)
+ env1.Foo('file1')
+ env2.Foo('file2')
+ </file>
+ </sconstruct>
+
+ <para>
+
+ In this example, the <filename>modify1.in</filename>
+ and <filename>modify2.in</filename> files
+ get added to the source lists
+ of the different commands:
+
+ </para>
+
+ <scons_output example="MY_EMITTER">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
</section>
&SCons; supports the ability for a Builder to modify the
lists of target(s) from the specified source(s).
+ You do this by defining an &emitter; function
+ that takes as its arguments
+ the list of the targets passed to the builder,
+ the list of the sources passed to the builder,
+ and the construction environment.
+ The emitter function should return the modified
+ lists of targets that should be built
+ and sources from which the targets will be built.
+
+ </para>
+
+ <para>
+
+ For example, suppose you want to define a Builder
+ that always calls a <filename>foobuild</filename> program,
+ and you want to automatically add
+ a new target file named
+ <filename>new_target</filename>
+ and a new source file named
+ <filename>new_source</filename>
+ whenever it's called.
+ The &SConstruct; file might look like this:
</para>
env.Foo('file')
</programlisting>
+ <para>
+
+ And would yield the following output:
+
+ </para>
+
<screen>
% <userinput>scons -Q</userinput>
foobuild file.foo new_target - file.input new_source
</screen>
+ <para>
+
+ One very flexible thing that you can is specify
+ use a construction variable to specify
+ different emitter functions for different
+ construction variable.
+ To do this, specify a string
+ containing a construction variable
+ expansion as the emitter when you call
+ the &Builder; function,
+ and set that construction variable to
+ the desired emitter function
+ in different construction environments:
+
+ </para>
+
<programlisting>
- bld = Builder(action = 'my_command',
- suffix = '.foo',
- src_suffix = '.input',
- emitter = 'MY_EMITTER')
- def modify1(target, source, env):
- return target, source
- def modify2(target, source, env):
- return target, source
- env1 = Environment(BUILDERS = {'Foo' : bld},
- MY_EMITTER = modify1)
- env2 = Environment(BUILDERS = {'Foo' : bld},
- MY_EMITTER = modify2)
- env1.Foo('file1')
- env2.Foo('file2')
+ bld = Builder(action = 'my_command $SOURCES > $TARGET',
+ suffix = '.foo',
+ src_suffix = '.input',
+ emitter = '$MY_EMITTER')
+ def modify1(target, source, env):
+ return target, source + ['modify1.in']
+ def modify2(target, source, env):
+ return target, source + ['modify2.in']
+ env1 = Environment(BUILDERS = {'Foo' : bld},
+ MY_EMITTER = modify1)
+ env2 = Environment(BUILDERS = {'Foo' : bld},
+ MY_EMITTER = modify2)
+ env1.Foo('file1')
+ env2.Foo('file2')
+ import os
+ env1['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd()
+ env2['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd()
+
+
</programlisting>
+ <programlisting>
+ bld = Builder(action = 'my_command $SOURCES > $TARGET',
+ suffix = '.foo',
+ src_suffix = '.input',
+ emitter = '$MY_EMITTER')
+ def modify1(target, source, env):
+ return target, source + ['modify1.in']
+ def modify2(target, source, env):
+ return target, source + ['modify2.in']
+ env1 = Environment(BUILDERS = {'Foo' : bld},
+ MY_EMITTER = modify1)
+ env2 = Environment(BUILDERS = {'Foo' : bld},
+ MY_EMITTER = modify2)
+ env1.Foo('file1')
+ env2.Foo('file2')
+
+ </programlisting>
+
+ <para>
+
+ In this example, the <filename>modify1.in</filename>
+ and <filename>modify2.in</filename> files
+ get added to the source lists
+ of the different commands:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ my_command file1.input modify1.in > file1.foo
+ my_command file2.input modify2.in > file2.foo
+ </screen>
+
</section>
<section>
<scons_output_command>scons -Q</scons_output_command>
</scons_output>
+ <para>
+
+ Note that the &CacheDir; feature still calculates
+ MD5 build sigantures for the shared cache file names
+ even if you configure &SCons; to use timestamps
+ to decide if files are up to date.
+ (See the <xref linkend="chap-depends"></xref>
+ chapter for information about the &Decider; function.)
+ Consequently, using &CacheDir; may reduce or eliminate any
+ potential performance improvements
+ from using timestamps for up-to-date decisions.
+
+ </para>
+
</section>
<section>
Retrieved `hello' from cache
</screen>
+ <para>
+
+ Note that the &CacheDir; feature still calculates
+ MD5 build sigantures for the shared cache file names
+ even if you configure &SCons; to use timestamps
+ to decide if files are up to date.
+ (See the <xref linkend="chap-depends"></xref>
+ chapter for information about the &Decider; function.)
+ Consequently, using &CacheDir; may reduce or eliminate any
+ potential performance improvements
+ from using timestamps for up-to-date decisions.
+
+ </para>
+
</section>
<section>
<para>
- &SCons; provides a number of ways that
- allow the writer of the &SConscript; files
- to give users a great deal of control over how to run the builds.
+ &SCons; provides a number of ways
+ for the writer of the &SConscript; files
+ to give the users who will run &SCons;
+ a great deal of control over the build execution.
+ The arguments that the user can specify on
+ the command line are broken down into three types:
</para>
- <section>
- <title>Not Having to Specify Command-Line Options Each Time: the &SCONSFLAGS; Environment Variable</title>
+ <variablelist>
- <para>
-
- Users may find themselves supplying
- the same command-line options every time
- they run &SCons;.
- For example, a user might find that it saves time
- to specify a value of <literal>-j 2</literal>
- to run the builds in parallel.
- To avoid having to type <literal>-j 2</literal> by hand
- every time,
- you can set the external environment variable
- &SCONSFLAGS; to a string containing
- command-line options that you want &SCons; to use.
-
- </para>
-
- <para>
-
- If, for example,
- you're using a POSIX shell that's
- compatible with the Bourne shell,
- and you always want &SCons; to use the
- <literal>-Q</literal> option,
- you can set the &SCONSFLAGS;
- environment as follows:
-
- </para>
-
- <scons_example name="SCONSFLAGS">
- <file name="SConstruct">
- def b(target, source, env):
- pass
- def s(target, source, env):
- return " ... [build output] ..."
- a = Action(b, strfunction = s)
- env = Environment(BUILDERS = {'A' : Builder(action=a)})
- env.A('foo.out', 'foo.in')
- </file>
- <file name="foo.in">
- foo.in
- </file>
- </scons_example>
-
- <scons_output example="SCONSFLAGS">
- <scons_output_command>scons</scons_output_command>
- <scons_output_command>export SCONSFLAGS="-Q"</scons_output_command>
- <scons_output_command environment="SCONSFLAGS=-Q">scons</scons_output_command>
- </scons_output>
+ <varlistentry>
+ <term>Options</term>
+ <listitem>
<para>
- Users of &csh;-style shells on POSIX systems
- can set the &SCONSFLAGS; environment as follows:
+ Command-line options always begin with
+ one or two <literal>-</literal> (hyphen) characters.
+ &SCons; provides ways for you to examind
+ and set options values from within your &SConscript; files,
+ as well as the ability to define your own
+ custom options.
+ See <xref linkend="sect-command-line-options"></xref>, below.
</para>
+ </listitem>
+ </varlistentry>
- <screen>
- $ <userinput>setenv SCONSFLAGS "-Q"</userinput>
- </screen>
+ <varlistentry>
+ <term>Variables</term>
+ <listitem>
<para>
- Windows users may typically want to set the
- &SCONSFLAGS; in the appropriate tab of the
- <literal>System Properties</literal> window.
+ Any command-line argument containing an <literal>=</literal>
+ (equal sign) is considered a variable setting with the form
+ <varname>variable</varname>=<varname>value</varname>
+ &SCons; provides direct access to
+ all of the command-line variable settings,
+ the ability to apply command-line variable settings
+ to construction environments,
+ and functions for configuring
+ specific types of variables
+ (Boolean values, path names, etc.)
+ with automatic validation of the user's specified values.
+ See <xref linkend="sect-command-line-variables"></xref>, below.
</para>
+ </listitem>
+ </varlistentry>
- </section>
-
- <section>
- <title>Getting at Command-Line Targets</title>
+ <varlistentry>
+ <term>Targets</term>
+ <listitem>
<para>
- &SCons; supports a &COMMAND_LINE_TARGETS; variable
- that lets you get at the list of targets that the
- user specified on the command line.
- You can use the targets to manipulate the
- build in any way you wish.
- As a simple example,
- suppose that you want to print a reminder
- to the user whenever a specific program is built.
- You can do this by checking for the
- target in the &COMMAND_LINE_TARGETS; list:
+ Any command-line argument that is not an option
+ or a variable setting
+ (does not begin with a hyphen
+ and does not contain an equal sign)
+ is considered a target that the user
+ (presumably) wants &SCons; to build.
+ A list of Node objects representing
+ the target or targets to build.
+ &SCons; provides access to the list of specified targets,
+ as well as ways to set the default list of targets
+ from within the &SConscript; files.
+ See <xref linkend="sect-command-line-targets"></xref>, below.
</para>
+ </listitem>
+ </varlistentry>
- <scons_example name="COMMAND_LINE_TARGETS">
- <file name="SConstruct" printme="1">
- if 'bar' in COMMAND_LINE_TARGETS:
- print "Don't forget to copy `bar' to the archive!"
- Default(Program('foo.c'))
- Program('bar.c')
- </file>
- <file name="foo.c">
- foo.c
- </file>
- <file name="bar.c">
- foo.c
- </file>
- </scons_example>
-
- <para>
-
- Then, running &SCons; with the default target
- works as it always does,
- but explicity specifying the &bar; target
- on the command line generates the warning message:
-
- </para>
+ </variablelist>
- <scons_output example="COMMAND_LINE_TARGETS">
- <scons_output_command>scons -Q</scons_output_command>
- <scons_output_command>scons -Q bar</scons_output_command>
- </scons_output>
+ <section id="sect-command-line-options">
+ <title>Command-Line Options</title>
<para>
- Another practical use for the &COMMAND_LINE_TARGETS; variable
- might be to speed up a build
- by only reading certain subsidiary &SConscript;
- files if a specific target is requested.
+ &SCons; has many <emphasis>command-line options</emphasis>
+ that control its behavior.
+ A &SCons; <emphasis>command-line option</emphasis>
+ always begins with one or two <literal>-</literal> (hyphen)
+ characters.
</para>
- </section>
-
- <section>
- <title>Controlling the Default Targets</title>
-
- <para>
+ <section>
+ <title>Not Having to Specify Command-Line Options Each Time: the &SCONSFLAGS; Environment Variable</title>
- One of the most basic things you can control
- is which targets &SCons; will build by default--that is,
- when there are no targets specified on the command line.
- As mentioned previously,
- &SCons; will normally build every target
- in or below the current directory
- by default--that is, when you don't
- explicitly specify one or more targets
- on the command line.
- Sometimes, however, you may want
- to specify explicitly that only
- certain programs, or programs in certain directories,
- should be built by default.
- You do this with the &Default; function:
+ <para>
- </para>
+ Users may find themselves supplying
+ the same command-line options every time
+ they run &SCons;.
+ For example, you might find it saves time
+ to specify a value of <literal>-j 2</literal>
+ to have &SCons; run up to two build commands in parallel.
+ To avoid having to type <literal>-j 2</literal> by hand
+ every time,
+ you can set the external environment variable
+ &SCONSFLAGS; to a string containing
+ command-line options that you want &SCons; to use.
- <scons_example name="Default1">
- <file name="SConstruct" printme="1">
- env = Environment()
- hello = env.Program('hello.c')
- env.Program('goodbye.c')
- Default(hello)
- </file>
- <file name="hello.c">
- hello.c
- </file>
- <file name="goodbye.c">
- goodbye.c
- </file>
- </scons_example>
+ </para>
- <para>
+ <para>
- This &SConstruct; file knows how to build two programs,
- &hello; and &goodbye;,
- but only builds the
- &hello; program by default:
+ If, for example,
+ you're using a POSIX shell that's
+ compatible with the Bourne shell,
+ and you always want &SCons; to use the
+ <literal>-Q</literal> option,
+ you can set the &SCONSFLAGS;
+ environment as follows:
- </para>
-
- <scons_output example="Default1">
- <scons_output_command>scons -Q</scons_output_command>
- <scons_output_command>scons -Q</scons_output_command>
- <scons_output_command>scons -Q goodbye</scons_output_command>
- </scons_output>
+ </para>
- <para>
+ <scons_example name="SCONSFLAGS">
+ <file name="SConstruct">
+ def b(target, source, env):
+ pass
+ def s(target, source, env):
+ return " ... [build output] ..."
+ a = Action(b, strfunction = s)
+ env = Environment(BUILDERS = {'A' : Builder(action=a)})
+ env.A('foo.out', 'foo.in')
+ </file>
+ <file name="foo.in">
+ foo.in
+ </file>
+ </scons_example>
- Note that, even when you use the &Default;
- function in your &SConstruct; file,
- you can still explicitly specify the current directory
- (<literal>.</literal>) on the command line
- to tell &SCons; to build
- everything in (or below) the current directory:
+ <scons_output example="SCONSFLAGS">
+ <scons_output_command>scons</scons_output_command>
+ <scons_output_command>export SCONSFLAGS="-Q"</scons_output_command>
+ <scons_output_command environment="SCONSFLAGS=-Q">scons</scons_output_command>
+ </scons_output>
- </para>
+ <para>
- <scons_output example="Default1">
- <scons_output_command>scons -Q .</scons_output_command>
- </scons_output>
+ Users of &csh;-style shells on POSIX systems
+ can set the &SCONSFLAGS; environment as follows:
- <para>
+ </para>
- You can also call the &Default;
- function more than once,
- in which case each call
- adds to the list of targets to be built by default:
+ <screen>
+ $ <userinput>setenv SCONSFLAGS "-Q"</userinput>
+ </screen>
- </para>
+ <para>
- <scons_example name="Default2">
- <file name="SConstruct" printme="1">
- env = Environment()
- prog1 = env.Program('prog1.c')
- Default(prog1)
- prog2 = env.Program('prog2.c')
- prog3 = env.Program('prog3.c')
- Default(prog3)
- </file>
- <file name="prog1.c">
- prog1.c
- </file>
- <file name="prog2.c">
- prog2.c
- </file>
- <file name="prog3.c">
- prog3.c
- </file>
- </scons_example>
+ Windows users may typically want to set the
+ &SCONSFLAGS; in the appropriate tab of the
+ <literal>System Properties</literal> window.
- <para>
+ </para>
- Or you can specify more than one target
- in a single call to the &Default; function:
+ </section>
- </para>
+ <section>
+ <title>Getting Values Set by Command-Line Options: the &GetOption; Function</title>
- <programlisting>
- env = Environment()
- prog1 = env.Program('prog1.c')
- prog2 = env.Program('prog2.c')
- prog3 = env.Program('prog3.c')
- Default(prog1, prog3)
- </programlisting>
+ <para>
- <para>
+ &SCons; provides the &GetOption; function
+ to get the values set by the various command-line options.
+ One common use of this is to check whether or not
+ the <literal>-h</literal> or <literal>--help</literal> option
+ has been specified.
+ Normally, &SCons; does not print its help text
+ until after it has read all of the &SConscript; files,
+ because it's possible that help text has been added
+ by some subsidiary &SConscript; file deep in the
+ source tree hierarchy.
+ Of course, reading all of the &SConscript; files
+ takes extra time.
- Either of these last two examples
- will build only the
- <application>prog1</application>
- and
- <application>prog3</application>
- programs by default:
+ </para>
- </para>
+ <para>
- <scons_output example="Default2">
- <scons_output_command>scons -Q</scons_output_command>
- <scons_output_command>scons -Q .</scons_output_command>
- </scons_output>
+ If you know that your configuration does not define
+ any additional help text in subsidiary &SConscript; files,
+ you can speed up the command-line help available to users
+ by using the &GetOption; function to load the
+ subsidiary &SConscript; files only if the
+ the user has <emphasis>not</emphasis> specified
+ the <literal>-h</literal> or <literal>--help</literal> option,
+ like so:
- <para>
+ </para>
- You can list a directory as
- an argument to &Default;:
+ <sconstruct)
+ if not GetOption('help'):
+ SConscript('src/SConscript', export='env')
+ </sconstruct>
- </para>
+ <para>
- <scons_example name="Default3">
- <file name="SConstruct" printme="1">
- env = Environment()
- env.Program(['prog1/main.c', 'prog1/foo.c'])
- env.Program(['prog2/main.c', 'prog2/bar.c'])
- Default('prog1')
- </file>
- <directory name="prog1"></directory>
- <directory name="prog2"></directory>
- <file name="prog1/main.c">
- int main() { printf("prog1/main.c\n"); }
- </file>
- <file name="prog1/foo.c">
- int foo() { printf("prog1/foo.c\n"); }
- </file>
- <file name="prog2/main.c">
- int main() { printf("prog2/main.c\n"); }
- </file>
- <file name="prog2/bar.c">
- int bar() { printf("prog2/bar.c\n"); }
- </file>
- </scons_example>
+ In general, the string that you pass to the
+ &GetOption; function to fetch the value of a command-line
+ option setting is the same as the "most common" long option name
+ (beginning with two hyphen characters),
+ although there are some exceptions.
+ The list of &SCons; command-line options
+ and the &GetOption; strings for fetching them,
+ are available in the
+ <xref linkend="sect-command-line-option-strings"></xref> section,
+ below.
- <para>
+ </para>
- In which case only the target(s) in that
- directory will be built by default:
+ </section>
- </para>
+ <section>
+ <title>Setting Values of Command-Line Options: the &SetOption; Function</title>
- <scons_output example="Default3">
- <scons_output_command>scons -Q</scons_output_command>
- <scons_output_command>scons -Q</scons_output_command>
- <scons_output_command>scons -Q .</scons_output_command>
- </scons_output>
+ <para>
- <para>
+ You can also set the values of &SCons;
+ command-line options from within the &SConscript; files
+ by using the &SetOption; function.
+ The strings that you use to set the values of &SCons;
+ command-line options are available in the
+ <xref linkend="sect-command-line-option-strings"></xref> section,
+ below.
- Lastly, if for some reason you don't want
- any targets built by default,
- you can use the Python <literal>None</literal>
- variable:
+ </para>
- </para>
+ <para>
- <scons_example name="Default4">
- <file name="SConstruct" printme="1">
- env = Environment()
- prog1 = env.Program('prog1.c')
- prog2 = env.Program('prog2.c')
- Default(None)
- </file>
- <file name="prog1.c">
- prog1.c
- </file>
- <file name="prog2.c">
- prog2.c
- </file>
- </scons_example>
+ One use of the &SetOption; function is to
+ specify a value for the <literal>-j</literal>
+ or <literal>--jobs</literal> option,
+ so that users get the improved performance
+ of a parallel build without having to specify the option by hand.
+ A complicating factor is that a good value
+ for the <literal>-j</literal> option is
+ somewhat system-dependent.
+ One rough guideline is that the more processors
+ your system has,
+ the higher you want to set the
+ <literal>-j</literal> value,
+ in order to take advantage of the number of CPUs.
- <para>
+ </para>
- Which would produce build output like:
+ <para>
- </para>
+ For example, suppose the administrators
+ of your development systems
+ have standardized on setting a
+ <varname>NUM_CPU</varname> environment variable
+ to the number of processors on each system.
+ A little bit of Python code
+ to access the environment variable
+ and the &SetOption; function
+ provide the right level of flexibility:
- <scons_output example="Default4">
- <scons_output_command>scons -Q</scons_output_command>
- <scons_output_command>scons -Q .</scons_output_command>
- </scons_output>
+ </para>
- <section>
- <title>Getting at the List of Default Targets</title>
+ <scons_example name="SetOption">
+ <file name="SConstruct" printme="1">
+ import os
+ num_cpu = int(os.environ.get('NUM_CPU', 2))
+ SetOption('num_jobs', num_cpu)
+ print "running with -j", GetOption('num_jobs')
+ </file>
+ <file name="foo.in">
+ foo.in
+ </file>
+ </scons_example>
<para>
- &SCons; supports a &DEFAULT_TARGETS; variable
- that lets you get at the current list of default targets.
- The &DEFAULT_TARGETS variable has
- two important differences from the &COMMAND_LINE_TARGETS; variable.
- First, the &DEFAULT_TARGETS; variable is a list of
- internal &SCons; nodes,
- so you need to convert the list elements to strings
- if you want to print them or look for a specific target name.
- Fortunately, you can do this easily
- by using the Python <function>map</function> function
- to run the list through <function>str</function>:
+ The above snippet of code
+ sets the value of the <literal>--jobs</literal> option
+ to the value specified in the
+ <varname>$NUM_CPU</varname> environment variable.
+ (This is one of the exception cases
+ where the string is spelled differently from
+ the from command-line option.
+ The string for fetching or setting the <literal>--jobs</literal>
+ value is <literal>num_jobs</literal>
+ for historical reasons.)
+ The code in this example prints the <literal>num_jobs</literal>
+ value for illustrative purposes.
+ It uses a default value of <literal>2</literal>
+ to provide some minimal parallelism even on
+ single-processor systems:
</para>
- <scons_example name="DEFAULT_TARGETS_1">
- <file name="SConstruct" printme="1">
- prog1 = Program('prog1.c')
- Default(prog1)
- print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS)
- </file>
- <file name="prog1.c">
- prog1.c
- </file>
- </scons_example>
+ <scons_output example="SetOption">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
<para>
- (Keep in mind that all of the manipulation of the
- &DEFAULT_TARGETS; list takes place during the
- first phase when &SCons; is reading up the &SConscript; files,
- which is obvious if
- we leave off the <literal>-Q</literal> flag when we run &SCons;:)
+ But if the <varname>$NUM_CPU</varname>
+ environment variable is set,
+ then we use that for the default number of jobs:
</para>
- <scons_output example="DEFAULT_TARGETS_1">
- <scons_output_command>scons</scons_output_command>
+ <scons_output example="SetOption">
+ <scons_output_command>export NUM_CPU="4"</scons_output_command>
+ <scons_output_command environment="NUM_CPU=4">scons -Q</scons_output_command>
</scons_output>
<para>
- Second,
- the contents of the &DEFAULT_TARGETS; list change
- in response to calls to the &Default: function,
- as you can see from the following &SConstruct; file:
+ But any explicit
+ <literal>-j</literal> or <literal>--jobs</literal>
+ value the user specifies an the command line is used first,
+ regardless of whether or not
+ the <varname>$NUM_CPU</varname> environment
+ variable is set:
</para>
- <scons_example name="DEFAULT_TARGETS_2">
- <file name="SConstruct" printme="1">
- prog1 = Program('prog1.c')
- Default(prog1)
- print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS)
- prog2 = Program('prog2.c')
- Default(prog2)
- print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS)
- </file>
- <file name="prog1.c">
- prog1.c
- </file>
- <file name="prog2.c">
- prog2.c
- </file>
- </scons_example>
+ <scons_output example="SetOption">
+ <scons_output_command>scons -Q -j 7</scons_output_command>
+ <scons_output_command>export NUM_CPU="4"</scons_output_command>
+ <scons_output_command environment="NUM_CPU=4">scons -Q -j 3</scons_output_command>
+ </scons_output>
+
+ </section>
+
+ <section id="sect-command-line-option-strings">
+ <title>Strings for Getting or Setting Values of &SCons; Command-Line Options</title>
<para>
- Which yields the output:
+ The strings that you can pass to the &GetOption;
+ and &SetOption; functions usually correspond to the
+ first long-form option name
+ (beginning with two hyphen characters: <literal>--</literal>),
+ after replacing any remaining hyphen characters
+ with underscores.
</para>
- <scons_output example="DEFAULT_TARGETS_2">
- <scons_output_command>scons</scons_output_command>
- </scons_output>
-
<para>
- In practice, this simply means that you
- need to pay attention to the order in
- which you call the &Default; function
- and refer to the &DEFAULT_TARGETS; list,
- to make sure that you don't examine the
- list before you've added the default targets
- you expect to find in it.
+ The full list of strings and the variables they
+ correspond to is as follows:
</para>
+ <informaltable>
+ <tgroup cols="2" align="left">
+
+ <thead>
+
+ <row>
+ <entry>String for &GetOption; and &SetOption;</entry>
+ <entry>Command-Line Option(s)</entry>
+ </row>
+
+ </thead>
+
+ <tbody>
+
+ <row>
+ <entry><literal>cache_debug</literal></entry>
+ <entry><option>--cache-debug</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>cache_disable</literal></entry>
+ <entry><option>--cache-disable</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>cache_force</literal></entry>
+ <entry><option>--cache-force</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>cache_show</literal></entry>
+ <entry><option>--cache-show</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>clean</literal></entry>
+ <entry><option>-c</option>,
+ <option>--clean</option>,
+ <option>--remove</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>config</literal></entry>
+ <entry><option>--config</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>directory</literal></entry>
+ <entry><option>-C</option>,
+ <option>--directory</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>diskcheck</literal></entry>
+ <entry><option>--diskcheck</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>duplicate</literal></entry>
+ <entry><option>--duplicate</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>file</literal></entry>
+ <entry><option>-f</option>,
+ <option>--file</option>,
+ <option>--makefile </option>,
+ <option>--sconstruct</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>help</literal></entry>
+ <entry><option>-h</option>,
+ <option>--help</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>ignore_errors</literal></entry>
+ <entry><option>--ignore-errors</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>implicit_cache</literal></entry>
+ <entry><option>--implicit-cache</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>implicit_deps_changed</literal></entry>
+ <entry><option>--implicit-deps-changed</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>implicit_deps_unchanged</literal></entry>
+ <entry><option>--implicit-deps-unchanged</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>interactive</literal></entry>
+ <entry><option>--interact</option>,
+ <option>--interactive</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>keep_going</literal></entry>
+ <entry><option>-k</option>,
+ <option>--keep-going</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>max_drift</literal></entry>
+ <entry><option>--max-drift</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>no_exec</literal></entry>
+ <entry><option>-n</option>,
+ <option>--no-exec</option>,
+ <option>--just-print</option>,
+ <option>--dry-run</option>,
+ <option>--recon</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>no_site_dir</literal></entry>
+ <entry><option>--no-site-dir</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>num_jobs</literal></entry>
+ <entry><option>-j</option>,
+ <option>--jobs</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>profile_file</literal></entry>
+ <entry><option>--profile</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>question</literal></entry>
+ <entry><option>-q</option>,
+ <option>--question</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>random</literal></entry>
+ <entry><option>--random</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>repository</literal></entry>
+ <entry><option>-Y</option>,
+ <option>--repository</option>,
+ <option>--srcdir</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>silent</literal></entry>
+ <entry><option>-s</option>,
+ <option>--silent</option>,
+ <option>--quiet</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>site_dir</literal></entry>
+ <entry><option>--site-dir</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>stack_size</literal></entry>
+ <entry><option>--stack-size</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>taskmastertrace_file</literal></entry>
+ <entry><option>--taskmastertrace</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>warn</literal></entry>
+ <entry><option>--warn</option> <option>--warning</option></entry>
+ </row>
+
+ </tbody>
+
+ </tgroup>
+ </informaltable>
+
</section>
- </section>
+ <section>
+ <title>Adding Custom Command-Line Options: the &AddOption; Function</title>
- <section>
- <title>Getting at the List of Build Targets, Regardless of Origin</title>
+ <para>
- <para>
+ &SCons; also allows you to define your own
+ command-line options with the &AddOption; function.
+ The &AddOption; function takes the same arguments
+ as the <function>optparse.add_option</function> function
+ from the standard Python library.
+ <footnote>
+ <para>
+ The &AddOption; function is,
+ in fact, implemented using a subclass
+ of the <classname>optparse.OptionParser</classname>.
+ </para>
+ </footnote>
+ Once you have added a custom command-line option
+ with the &AddOption; function,
+ the value of the option (if any) is immediately available
+ using the standard &GetOption; function.
+ (The value can also be set using &SetOption;,
+ although that's not very useful in practice
+ because a default value can be specified in
+ directly in the &AddOption; call.)
- We've already been introduced to the
- &COMMAND_LINE_TARGETS; variable,
- which contains a list of targets specified on the command line,
- and the &DEFAULT_TARGETS; variable,
- which contains a list of targets specified
- via calls to the &Default; method or function.
- Sometimes, however,
- you want a list of whatever targets
- &SCons; will try to build,
- regardless of whether the targets came from the
- command line or a &Default; call.
- You could code this up by hand, as follows:
+ </para>
- </para>
+ <para>
- <sconstruct>
- if COMMAND_LINE_TARGETS:
- targets = COMMAND_LINE_TARGETS
- else:
- targets = DEFAULT_TARGETS
- </sconstruct>
+ One useful example of using this functionality
+ is to provide a <option>--prefix</option> for users:
- <para>
+ </para>
- &SCons;, however, provides a convenient
- &BUILD_TARGETS; variable
- that eliminates the need for this by-hand manipulation.
- Essentially, the &BUILD_TARGETS; variable
- contains a list of the command-line targets,
- if any were specified,
- and if no command-line targets were specified,
- it contains a list of the targets specified
- via the &Default; method or function.
+ <scons_example name="AddOption">
+ <file name="SConstruct" printme="1">
+ AddOption('--prefix',
+ dest='prefix',
+ type='string',
+ nargs=1,
+ action='store',
+ metavar='DIR',
+ help='installation prefix')
+
+ env = Environment(PREFIX = GetOption('prefix'))
+
+ installed_foo = env.Install('$PREFIX/usr/bin', 'foo.in')
+ Default(installed_foo)
+ </file>
+ <file name="foo.in">
+ foo.in
+ </file>
+ </scons_example>
- </para>
+ <para>
- <para>
+ The above code uses the &GetOption; function
+ to set the <varname>$PREFIX</varname>
+ construction variable to any
+ value that the user specifies with a command-line
+ option of <literal>--prefix</literal>.
+ Because <varname>$PREFIX</varname>
+ will expand to a null string if it's not initialized,
+ running &SCons; without the
+ option of <literal>--prefix</literal>
+ will install the file in the
+ <filename>/usr/bin/</filename> directory:
- Because &BUILD_TARGETS; may contain a list of &SCons; nodes,
- you must convert the list elements to strings
- if you want to print them or look for a specific target name,
- just like the &DEFAULT_TARGETS; list:
+ </para>
- </para>
+ <scons_output example="AddOption">
+ <scons_output_command>scons -Q -n</scons_output_command>
+ </scons_output>
- <scons_example name="BUILD_TARGETS_1">
- <file name="SConstruct" printme="1">
- prog1 = Program('prog1.c')
- Program('prog2.c')
- Default(prog1)
- print "BUILD_TARGETS is", map(str, BUILD_TARGETS)
- </file>
- <file name="prog1.c">
- prog1.c
- </file>
- <file name="prog2.c">
- prog2.c
- </file>
- </scons_example>
+ <para>
- <para>
+ But specifying <literal>--prefix=/tmp/install</literal>
+ on the command line causes the file to be installed in the
+ <filename>/tmp/install/usr/bin/</filename> directory:
- Notice how the value of &BUILD_TARGETS;
- changes depending on whether a target is
- specified on the command line:
+ </para>
- </para>
+ <scons_output example="AddOption">
+ <scons_output_command>scons -Q -n --prefix=/tmp/install</scons_output_command>
+ </scons_output>
- <scons_output example="BUILD_TARGETS_1">
- <scons_output_command>scons -Q</scons_output_command>
- <scons_output_command>scons -Q prog2</scons_output_command>
- <scons_output_command>scons -Q -c .</scons_output_command>
- </scons_output>
+ </section>
</section>
- <section>
- <title>Command-Line <varname>variable</varname>=<varname>value</varname> Build Options</title>
+ <section id="sect-command-line-variables">
+ <title>Command-Line <varname>variable</varname>=<varname>value</varname> Build Variables</title>
<para>
to specifications on the command line.
(Note that unless you want to require
that users <emphasis>always</emphasis>
- specify an option,
+ specify a variable,
you probably want to use
the Python
<literal>ARGUMENTS.get()</literal> function,
</para>
- </section>
-
- <section>
- <title>Controlling Command-Line Build Options</title>
-
<para>
- Being able to use a command-line build option like
- <literal>debug=1</literal> is handy,
- but it can be a chore to write specific Python code
- to recognize each such option
- and apply the values to a construction variable.
- To help with this,
- &SCons; supports a class to
- define such build options easily,
- and a mechanism to apply the
- build options to a construction environment.
- This allows you to control how the build options affect
- construction environments.
+ The &ARGUMENTS; dictionary has two minor drawbacks.
+ First, because it is a dictionary,
+ it can only store one value for each specified keyword,
+ and thus only "remembers" the last setting
+ for each keyword on the command line.
+ This makes the &ARGUMENTS; dictionary
+ inappropriate if users should be able to
+ specify multiple values
+ on the command line for a given keyword.
+ Second, it does not preserve
+ the order in which the variable settings
+ were specified,
+ which is a problem if
+ you want the configuration to
+ behave differently in response
+ to the order in which the build
+ variable settings were specified on the command line.
</para>
<para>
- For example, suppose that you want users to set
- a &RELEASE; construction variable on the
- command line whenever the time comes to build
- a program for release,
- and that the value of this variable
- should be added to the command line
- with the appropriate <literal>-D</literal> option
- (or other command line option)
- to pass the value to the C compiler.
- Here's how you might do that by setting
- the appropriate value in a dictionary for the
- &cv-link-CPPDEFINES; construction variable:
+ To accomodate these requirements,
+ &SCons; provides an &ARGLIST; variable
+ that gives you direct access to
+ <varname>variable</varname>=<varname>value</varname>
+ settings on the command line,
+ in the exact order they were specified,
+ and without removing any duplicate settings.
+ Each element in the &ARGLIST; variable
+ is itself a two-element list
+ containing the keyword and the value
+ of the setting,
+ and you must loop through,
+ or otherwise select from,
+ the elements of &ARGLIST; to
+ process the specific settings you want
+ in whatever way is appropriate for your configuration.
+ For example,
+ the following code to let the user
+ add to the &CPPDEFINES; construction variable
+ by specifying multiple
+ <varname>define=</varname>
+ settings on the command line:
</para>
- <scons_example name="Options1">
- <file name="SConstruct" printme="1">
- opts = Options()
- opts.Add('RELEASE', 'Set to 1 to build for release', 0)
- env = Environment(options = opts,
- CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
- env.Program(['foo.c', 'bar.c'])
- </file>
- <file name="foo.c">
- foo.c
- </file>
- <file name="bar.c">
- bar.c
- </file>
+ <scons_example name="ARGLIST">
+ <file name="SConstruct" printme="1">
+ cppdefines = []
+ for key, value in ARGLIST:
+ if key == 'define':
+ cppdefines.append(value)
+ env = Environment(CPPDEFINES = cppdefines)
+ env.Object('prog.c')
+ </file>
+ <file name="prog.c">
+ prog.c
+ </file>
</scons_example>
<para>
- This &SConstruct; file first creates an
- &Options; object
- (the <literal>opts = Options()</literal> call),
- and then uses the object's &Add;
- method to indicate that the &RELEASE;
- option can be set on the command line,
- and that it's default value will be <literal>0</literal>
- (the third argument to the &Add; method).
- The second argument is a line of help text;
- we'll learn how to use it in the next section.
+ Yields the followig output:
</para>
+ <scons_output example="ARGLIST">
+ <scons_output_command>scons -Q define=FOO</scons_output_command>
+ <scons_output_command>scons -Q define=FOO define=BAR</scons_output_command>
+ </scons_output>
+
<para>
- We then pass the created &Options;
- object as an &options; keyword argument
- to the &Environment; call
- used to create the construction environment.
- This then allows a user to set the
- &RELEASE; build option on the command line
- and have the variable show up in
- the command line used to build each object from
- a C source file:
+ Note that the &ARGLIST; and &ARGUMENTS;
+ variables do not interfere with each other,
+ but merely provide slightly different views
+ into how the user specified
+ <varname>variable</varname>=<varname>value</varname>
+ settings on the command line.
+ You can use both variables in the same
+ &SCons; configuration.
+ In general, the &ARGUMENTS; dictionary
+ is more convenient to use,
+ (since you can just fetch variable
+ settings through a dictionary access),
+ and the &ARGLIST; list
+ is more flexible
+ (since you can examine the
+ specific order in which
+ the user's command-line variabe settings).
</para>
- <scons_output example="Options1">
- <scons_output_command>scons -Q RELEASE=1</scons_output_command>
- </scons_output>
-
- </section>
+ <section>
+ <title>Controlling Command-Line Build Variables</title>
- <section>
- <title>Providing Help for Command-Line Build Options</title>
+ <para>
- <para>
+ Being able to use a command-line build variable like
+ <literal>debug=1</literal> is handy,
+ but it can be a chore to write specific Python code
+ to recognize each such variable,
+ check for errors and provide appropriate messages,
+ and apply the values to a construction variable.
+ To help with this,
+ &SCons; supports a class to
+ define such build variables easily,
+ and a mechanism to apply the
+ build variables to a construction environment.
+ This allows you to control how the build variables affect
+ construction environments.
- To make command-line build options most useful,
- you ideally want to provide
- some help text that will describe
- the available options
- when the user runs <literal>scons -h</literal>.
- You could write this text by hand,
- but &SCons; provides an easier way.
- &Options; objects support a
- &GenerateHelpText; method
- that will, as its name indicates,
- generate text that describes
- the various options that
- have been added to it.
- You then pass the output from this method to
- the &Help; function:
+ </para>
- </para>
+ <para>
- <scons_example name="Options_Help">
- <file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add('RELEASE', 'Set to 1 to build for release', 0)
- env = Environment(options = opts)
- Help(opts.GenerateHelpText(env))
- </file>
- </scons_example>
+ For example, suppose that you want users to set
+ a &RELEASE; construction variable on the
+ command line whenever the time comes to build
+ a program for release,
+ and that the value of this variable
+ should be added to the command line
+ with the appropriate <literal>-D</literal> option
+ (or other command line option)
+ to pass the value to the C compiler.
+ Here's how you might do that by setting
+ the appropriate value in a dictionary for the
+ &cv-link-CPPDEFINES; construction variable:
- <para>
+ </para>
- &SCons; will now display some useful text
- when the <literal>-h</literal> option is used:
+ <scons_example name="Variables1">
+ <file name="SConstruct" printme="1">
+ vars = Variables()
+ vars.Add('RELEASE', 'Set to 1 to build for release', 0)
+ env = Environment(variables = vars,
+ CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
+ env.Program(['foo.c', 'bar.c'])
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ <file name="bar.c">
+ bar.c
+ </file>
+ </scons_example>
- </para>
+ <para>
- <scons_output example="Options_Help">
- <scons_output_command>scons -Q -h</scons_output_command>
- </scons_output>
+ This &SConstruct; file first creates a &Variables; object
+ (the <literal>vars = Variables()</literal> call),
+ and then uses the object's &Add;
+ method to indicate that the &RELEASE;
+ variable can be set on the command line,
+ and that its default value will be <literal>0</literal>
+ (the third argument to the &Add; method).
+ The second argument is a line of help text;
+ we'll learn how to use it in the next section.
- <para>
+ </para>
- Notice that the help output shows the default value,
- and the current actual value of the build option.
+ <para>
- </para>
+ We then pass the created &Variables;
+ object as a &variables; keyword argument
+ to the &Environment; call
+ used to create the construction environment.
+ This then allows a user to set the
+ &RELEASE; build variable on the command line
+ and have the variable show up in
+ the command line used to build each object from
+ a C source file:
- </section>
+ </para>
- <section>
- <title>Reading Build Options From a File</title>
+ <scons_output example="Variables1">
+ <scons_output_command>scons -Q RELEASE=1</scons_output_command>
+ </scons_output>
- <para>
+ <para>
- Being able to use a command-line build option like
- <literal>debug=1</literal> is handy,
- but it can be a chore to write specific Python code
- to recognize each such option
- and apply the values to a construction variable.
- To help with this,
- &SCons; supports a class to
- define such build options easily
- and to read build option values from a file.
- This allows you to control how the build options affect
- construction environments.
- The way you do this is by specifying
- a file name when you call &Options;,
- like &custom_py; in the following example:
+ NOTE: Before &SCons; release 0.98.1, these build variables
+ were known as "command-line build options."
+ The class was actually named the &Options; class,
+ and in the sections below,
+ the various functions were named
+ &BoolOption;, &EnumOption;, &ListOption;,
+ &PathOption;, &PackageOption; and &AddOptions;.
+ These older names still work,
+ and you may encounter them in older
+ &SConscript; fles,
+ but their use is discouraged
+ and will be officially deprecated some day.
- </para>
+ </para>
- <scons_example name="Options_custom_py_1">
- <file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add('RELEASE', 'Set to 1 to build for release', 0)
- env = Environment(options = opts,
- CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
- env.Program(['foo.c', 'bar.c'])
- Help(opts.GenerateHelpText(env))
- </file>
- <file name="foo.c">
- foo.c
- </file>
- <file name="bar.c">
- bar.c
- </file>
- <file name="custom.py">
- RELEASE = 1
- </file>
- </scons_example>
+ </section>
- <para>
+ <section>
+ <title>Providing Help for Command-Line Build Variables</title>
- This then allows us to control the &RELEASE;
- variable by setting it in the &custom_py; file:
+ <para>
- </para>
+ To make command-line build variables most useful,
+ you ideally want to provide
+ some help text that will describe
+ the available variables
+ when the user runs <literal>scons -h</literal>.
+ You could write this text by hand,
+ but &SCons; provides an easier way.
+ &Variables; objects support a
+ &GenerateHelpText; method
+ that will, as its name suggests,
+ generate text that describes
+ the various variables that
+ have been added to it.
+ You then pass the output from this method to
+ the &Help; function:
- <scons_example_file example="Options_custom_py_1" name="custom.py"></scons_example_file>
+ </para>
- <para>
+ <scons_example name="Variables_Help">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add('RELEASE', 'Set to 1 to build for release', 0)
+ env = Environment(variables = vars)
+ Help(vars.GenerateHelpText(env))
+ </file>
+ </scons_example>
- Note that this file is actually executed
- like a Python script.
- Now when we run &SCons;:
+ <para>
- </para>
+ &SCons; will now display some useful text
+ when the <literal>-h</literal> option is used:
- <scons_output example="Options_custom_py_1">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ </para>
- <para>
+ <scons_output example="Variables_Help">
+ <scons_output_command>scons -Q -h</scons_output_command>
+ </scons_output>
- And if we change the contents of &custom_py; to:
+ <para>
- </para>
+ Notice that the help output shows the default value,
+ and the current actual value of the build variable.
- <scons_example name="Options_custom_py_2">
- <file name="SConstruct">
- opts = Options('custom.py')
- opts.Add('RELEASE', 'Set to 1 to build for release', 0)
- env = Environment(options = opts,
- CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
- env.Program(['foo.c', 'bar.c'])
- Help(opts.GenerateHelpText(env))
- </file>
- <file name="foo.c">
- foo.c
- </file>
- <file name="bar.c">
- bar.c
- </file>
- <file name="custom.py" printme="1">
- RELEASE = 0
- </file>
- </scons_example>
+ </para>
- <para>
+ </section>
- The object files are rebuilt appropriately
- with the new option:
+ <section>
+ <title>Reading Build Variables From a File</title>
- </para>
+ <para>
- <scons_output example="Options_custom_py_2">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ Giving the user a way to specify the
+ value of a build variable on the command line
+ is useful,
+ but can still be tedious
+ if users must specify the variable
+ every time they run &SCons;.
+ We can let users provide customized build variable settings
+ in a local file by providing a
+ file name when we create the
+ &Variables; object:
- </section>
+ </para>
- <section>
- <title>Canned Build Options</title>
+ <scons_example name="Variables_custom_py_1">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add('RELEASE', 'Set to 1 to build for release', 0)
+ env = Environment(variables = vars,
+ CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
+ env.Program(['foo.c', 'bar.c'])
+ Help(vars.GenerateHelpText(env))
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ <file name="bar.c">
+ bar.c
+ </file>
+ <file name="custom.py">
+ RELEASE = 1
+ </file>
+ </scons_example>
- <para>
+ <para>
- &SCons; provides a number of functions
- that provide ready-made behaviors
- for various types of command-line build options.
+ This then allows the user to control the &RELEASE;
+ variable by setting it in the &custom_py; file:
- </para>
+ </para>
- <section>
- <title>True/False Values: the &BoolOption; Build Option</title>
+ <scons_example_file example="Variables_custom_py_1" name="custom.py"></scons_example_file>
<para>
- It's often handy to be able to specify an
- option that controls a simple Boolean variable
- with a &true; or &false; value.
- It would be even more handy to accomodate
- users who have different preferences for how to represent
- &true; or &false; values.
- The &BoolOption; function
- makes it easy to accomodate a variety of
- common values that represent
- &true; or &false;.
+ Note that this file is actually executed
+ like a Python script.
+ Now when we run &SCons;:
</para>
+ <scons_output example="Variables_custom_py_1">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
<para>
- The &BoolOption; function takes three arguments:
- the name of the build option,
- the default value of the build option,
- and the help string for the option.
- It then returns appropriate information for
- passing to the &Add; method of an &Options; object, like so:
+ And if we change the contents of &custom_py; to:
</para>
- <scons_example name="BoolOption">
- <file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add(BoolOption('RELEASE', 'Set to build for release', 0))
- env = Environment(options = opts,
+ <scons_example name="Variables_custom_py_2">
+ <file name="SConstruct">
+ vars = Variables('custom.py')
+ vars.Add('RELEASE', 'Set to 1 to build for release', 0)
+ env = Environment(variables = vars,
CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
- env.Program('foo.c')
+ env.Program(['foo.c', 'bar.c'])
+ Help(vars.GenerateHelpText(env))
</file>
<file name="foo.c">
foo.c
</file>
+ <file name="bar.c">
+ bar.c
+ </file>
+ <file name="custom.py" printme="1">
+ RELEASE = 0
+ </file>
</scons_example>
<para>
- With this build option,
- the &RELEASE; variable can now be enabled by
- setting it to the value <literal>yes</literal>
- or <literal>t</literal>:
+ The object files are rebuilt appropriately
+ with the new variable:
</para>
- <scons_output example="BoolOption">
- <scons_output_command>scons -Q RELEASE=yes foo.o</scons_output_command>
+ <scons_output example="Variables_custom_py_2">
+ <scons_output_command>scons -Q</scons_output_command>
</scons_output>
- <scons_output example="BoolOption">
- <scons_output_command>scons -Q RELEASE=t foo.o</scons_output_command>
- </scons_output>
-
- <para>
-
- Other values that equate to &true; include
- <literal>y</literal>,
- <literal>1</literal>,
- <literal>on</literal>
- and
- <literal>all</literal>.
+ </section>
- </para>
+ <section>
+ <title>Pre-Defined Build Variable Functions</title>
<para>
- Conversely, &RELEASE; may now be given a &false;
- value by setting it to
- <literal>no</literal>
- or
- <literal>f</literal>:
+ &SCons; provides a number of functions
+ that provide ready-made behaviors
+ for various types of command-line build variables.
</para>
- <scons_output example="BoolOption">
- <scons_output_command>scons -Q RELEASE=no foo.o</scons_output_command>
- </scons_output>
+ <section>
+ <title>True/False Values: the &BoolVariable; Build Variable Function</title>
- <scons_output example="BoolOption">
- <scons_output_command>scons -Q RELEASE=f foo.o</scons_output_command>
- </scons_output>
+ <para>
- <para>
+ It's often handy to be able to specify a
+ variable that controls a simple Boolean variable
+ with a &true; or &false; value.
+ It would be even more handy to accomodate
+ users who have different preferences for how to represent
+ &true; or &false; values.
+ The &BoolVariable; function
+ makes it easy to accomodate these
+ common representations of
+ &true; or &false;.
- Other values that equate to &false; include
- <literal>n</literal>,
- <literal>0</literal>,
- <literal>off</literal>
- and
- <literal>none</literal>.
+ </para>
- </para>
+ <para>
- <para>
+ The &BoolVariable; function takes three arguments:
+ the name of the build variable,
+ the default value of the build variable,
+ and the help string for the variable.
+ It then returns appropriate information for
+ passing to the &Add; method of a &Variables; object, like so:
- Lastly, if a user tries to specify
- any other value,
- &SCons; supplies an appropriate error message:
+ </para>
- </para>
+ <scons_example name="BoolVariable">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add(BoolVariable('RELEASE', 'Set to build for release', 0))
+ env = Environment(variables = vars,
+ CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ </scons_example>
+
+ <para>
+
+ With this build variable,
+ the &RELEASE; variable can now be enabled by
+ setting it to the value <literal>yes</literal>
+ or <literal>t</literal>:
+
+ </para>
+
+ <scons_output example="BoolVariable">
+ <scons_output_command>scons -Q RELEASE=yes foo.o</scons_output_command>
+ </scons_output>
+
+ <scons_output example="BoolVariable">
+ <scons_output_command>scons -Q RELEASE=t foo.o</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ Other values that equate to &true; include
+ <literal>y</literal>,
+ <literal>1</literal>,
+ <literal>on</literal>
+ and
+ <literal>all</literal>.
+
+ </para>
- <scons_output example="BoolOption">
- <scons_output_command>scons -Q RELEASE=bad_value foo.o</scons_output_command>
- </scons_output>
+ <para>
+
+ Conversely, &RELEASE; may now be given a &false;
+ value by setting it to
+ <literal>no</literal>
+ or
+ <literal>f</literal>:
+
+ </para>
+
+ <scons_output example="BoolVariable">
+ <scons_output_command>scons -Q RELEASE=no foo.o</scons_output_command>
+ </scons_output>
+
+ <scons_output example="BoolVariable">
+ <scons_output_command>scons -Q RELEASE=f foo.o</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ Other values that equate to &false; include
+ <literal>n</literal>,
+ <literal>0</literal>,
+ <literal>off</literal>
+ and
+ <literal>none</literal>.
+
+ </para>
+
+ <para>
+
+ Lastly, if a user tries to specify
+ any other value,
+ &SCons; supplies an appropriate error message:
+
+ </para>
+
+ <scons_output example="BoolVariable">
+ <scons_output_command>scons -Q RELEASE=bad_value foo.o</scons_output_command>
+ </scons_output>
+
+ </section>
+
+ <section>
+ <title>Single Value From a List: the &EnumVariable; Build Variable Function</title>
+
+ <para>
+
+ Suppose that we want a user to be able to
+ set a &COLOR; variable
+ that selects a background color to be
+ displayed by an application,
+ but that we want to restrict the
+ choices to a specific set of allowed colors.
+ This can be set up quite easily
+ using the &EnumVariable;,
+ which takes a list of &allowed_values
+ in addition to the variable name,
+ default value,
+ and help text arguments:
+
+ </para>
+
+ <scons_example name="EnumVariable">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add(EnumVariable('COLOR', 'Set background color', 'red',
+ allowed_values=('red', 'green', 'blue')))
+ env = Environment(variables = vars,
+ CPPDEFINES={'COLOR' : '"${COLOR}"'})
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ </scons_example>
+
+ <para>
+
+ The user can now explicity set the &COLOR; build variable
+ to any of the specified allowed values:
+
+ </para>
+
+ <scons_output example="EnumVariable">
+ <scons_output_command>scons -Q COLOR=red foo.o</scons_output_command>
+ <scons_output_command>scons -Q COLOR=blue foo.o</scons_output_command>
+ <scons_output_command>scons -Q COLOR=green foo.o</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ But, almost more importantly,
+ an attempt to set &COLOR;
+ to a value that's not in the list
+ generates an error message:
+
+ </para>
+
+ <scons_output example="EnumVariable">
+ <scons_output_command>scons -Q COLOR=magenta foo.o</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ The &EnumVariable; function also supports a way
+ to map alternate names to allowed values.
+ Suppose, for example,
+ that we want to allow the user
+ to use the word <literal>navy</literal> as a synonym for
+ <literal>blue</literal>.
+ We do this by adding a ↦ dictionary
+ that will map its key values
+ to the desired legal value:
+
+ </para>
+
+ <scons_example name="EnumVariable_map">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add(EnumVariable('COLOR', 'Set background color', 'red',
+ allowed_values=('red', 'green', 'blue'),
+ map={'navy':'blue'}))
+ env = Environment(variables = vars,
+ CPPDEFINES={'COLOR' : '"${COLOR}"'})
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ </scons_example>
+
+ <para>
+
+ As desired, the user can then use
+ <literal>navy</literal> on the command line,
+ and &SCons; will translate it into <literal>blue</literal>
+ when it comes time to use the &COLOR;
+ variable to build a target:
+
+ </para>
+
+ <scons_output example="EnumVariable_map">
+ <scons_output_command>scons -Q COLOR=navy foo.o</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ By default, when using the &EnumVariable; function,
+ arguments that differ
+ from the legal values
+ only in case
+ are treated as illegal values:
+
+ </para>
+
+ <scons_output example="EnumVariable">
+ <scons_output_command>scons -Q COLOR=Red foo.o</scons_output_command>
+ <scons_output_command>scons -Q COLOR=BLUE foo.o</scons_output_command>
+ <scons_output_command>scons -Q COLOR=nAvY foo.o</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ The &EnumVariable; function can take an additional
+ &ignorecase; keyword argument that,
+ when set to <literal>1</literal>,
+ tells &SCons; to allow case differences
+ when the values are specified:
+
+ </para>
+
+ <scons_example name="EnumVariable_ic1">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add(EnumVariable('COLOR', 'Set background color', 'red',
+ allowed_values=('red', 'green', 'blue'),
+ map={'navy':'blue'},
+ ignorecase=1))
+ env = Environment(variables = vars,
+ CPPDEFINES={'COLOR' : '"${COLOR}"'})
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ </scons_example>
+
+ <para>
+
+ Which yields the output:
+
+ </para>
+
+ <scons_output example="EnumVariable_ic1">
+ <scons_output_command>scons -Q COLOR=Red foo.o</scons_output_command>
+ <scons_output_command>scons -Q COLOR=BLUE foo.o</scons_output_command>
+ <scons_output_command>scons -Q COLOR=nAvY foo.o</scons_output_command>
+ <scons_output_command>scons -Q COLOR=green foo.o</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ Notice that an &ignorecase; value of <literal>1</literal>
+ preserves the case-spelling that the user supplied.
+ If you want &SCons; to translate the names
+ into lower-case,
+ regardless of the case used by the user,
+ specify an &ignorecase; value of <literal>2</literal>:
+
+ </para>
+
+ <scons_example name="EnumVariable_ic2">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add(EnumVariable('COLOR', 'Set background color', 'red',
+ allowed_values=('red', 'green', 'blue'),
+ map={'navy':'blue'},
+ ignorecase=2))
+ env = Environment(variables = vars,
+ CPPDEFINES={'COLOR' : '"${COLOR}"'})
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ </scons_example>
+
+ <para>
+
+ Now &SCons; will use values of
+ <literal>red</literal>,
+ <literal>green</literal> or
+ <literal>blue</literal>
+ regardless of how the user spells
+ those values on the command line:
+
+ </para>
+
+ <scons_output example="EnumVariable_ic2">
+ <scons_output_command>scons -Q COLOR=Red foo.o</scons_output_command>
+ <scons_output_command>scons -Q COLOR=nAvY foo.o</scons_output_command>
+ <scons_output_command>scons -Q COLOR=GREEN foo.o</scons_output_command>
+ </scons_output>
+
+ </section>
+
+ <section>
+ <title>Multiple Values From a List: the &ListVariable; Build Variable Function</title>
+
+ <para>
+
+ Another way in which you might want to allow users
+ to control a build variable is to
+ specify a list of one or more legal values.
+ &SCons; supports this through the &ListVariable; function.
+ If, for example, we want a user to be able to set a
+ &COLORS; variable to one or more of the legal list of values:
+
+ </para>
+
+ <scons_example name="ListVariable">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add(ListVariable('COLORS', 'List of colors', 0,
+ ['red', 'green', 'blue']))
+ env = Environment(variables = vars,
+ CPPDEFINES={'COLORS' : '"${COLORS}"'})
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ </scons_example>
+
+ <para>
+
+ A user can now specify a comma-separated list
+ of legal values,
+ which will get translated into a space-separated
+ list for passing to the any build commands:
+
+ </para>
+
+ <scons_output example="ListVariable">
+ <scons_output_command>scons -Q COLORS=red,blue foo.o</scons_output_command>
+ <scons_output_command>scons -Q COLORS=blue,green,red foo.o</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ In addition, the &ListVariable; function
+ allows the user to specify explicit keywords of
+ &all; or &none;
+ to select all of the legal values,
+ or none of them, respectively:
+
+ </para>
+
+ <scons_output example="ListVariable">
+ <scons_output_command>scons -Q COLORS=all foo.o</scons_output_command>
+ <scons_output_command>scons -Q COLORS=none foo.o</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ And, of course, an illegal value
+ still generates an error message:
+
+ </para>
+
+ <scons_output example="ListVariable">
+ <scons_output_command>scons -Q COLORS=magenta foo.o</scons_output_command>
+ </scons_output>
+
+ </section>
+
+ <section>
+ <title>Path Names: the &PathVariable; Build Variable Function</title>
+
+ <para>
+
+ &SCons; supports a &PathVariable; function
+ to make it easy to create a build variable
+ to control an expected path name.
+ If, for example, you need to
+ define a variable in the preprocessor
+ that controls the location of a
+ configuration file:
+
+ </para>
+
+ <scons_example name="PathVariable">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add(PathVariable('CONFIG',
+ 'Path to configuration file',
+ '__ROOT__/etc/my_config'))
+ env = Environment(variables = vars,
+ CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'})
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ <file name="__ROOT__/etc/my_config">
+ /opt/location
+ </file>
+ <file name="__ROOT__/usr/local/etc/other_config">
+ /opt/location
+ </file>
+ </scons_example>
+
+ <para>
+
+ This then allows the user to
+ override the &CONFIG; build variable
+ on the command line as necessary:
+
+ </para>
+
+ <scons_output example="PathVariable">
+ <scons_output_command>scons -Q foo.o</scons_output_command>
+ <scons_output_command>scons -Q CONFIG=__ROOT__/usr/local/etc/other_config foo.o</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ By default, &PathVariable; checks to make sure
+ that the specified path exists and generates an error if it
+ doesn't:
+
+ </para>
+
+ <scons_output example="PathVariable">
+ <scons_output_command>scons -Q CONFIG=__ROOT__/does/not/exist foo.o</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ &PathVariable; provides a number of methods
+ that you can use to change this behavior.
+ If you want to ensure that any specified paths are,
+ in fact, files and not directories,
+ use the &PathVariable_PathIsFile; method:
+
+ </para>
+
+ <scons_example name="PathIsFile">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add(PathVariable('CONFIG',
+ 'Path to configuration file',
+ '__ROOT__/etc/my_config',
+ PathVariable.PathIsFile))
+ env = Environment(variables = vars,
+ CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'})
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ <file name="__ROOT__/etc/my_config">
+ /opt/location
+ </file>
+ </scons_example>
+
+ <para>
+
+ Conversely, to ensure that any specified paths are
+ directories and not files,
+ use the &PathVariable_PathIsDir; method:
+
+ </para>
+
+ <scons_example name="PathIsDir">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add(PathVariable('DBDIR',
+ 'Path to database directory',
+ '__ROOT__/var/my_dbdir',
+ PathVariable.PathIsDir))
+ env = Environment(variables = vars,
+ CPPDEFINES={'DBDIR' : '"$DBDIR"'})
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ <file name="__ROOT__/var/my_dbdir">
+ /opt/location
+ </file>
+ </scons_example>
+
+ <para>
+
+ If you want to make sure that any specified paths
+ are directories,
+ and you would like the directory created
+ if it doesn't already exist,
+ use the &PathVariable_PathIsDirCreate; method:
+
+ </para>
+
+ <scons_example name="PathIsDirCreate">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add(PathVariable('DBDIR',
+ 'Path to database directory',
+ '__ROOT__/var/my_dbdir',
+ PathVariable.PathIsDirCreate))
+ env = Environment(variables = vars,
+ CPPDEFINES={'DBDIR' : '"$DBDIR"'})
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ <file name="__ROOT__/var/my_dbdir">
+ /opt/location
+ </file>
+ </scons_example>
+
+ <para>
+
+ Lastly, if you don't care whether the path exists,
+ is a file, or a directory,
+ use the &PathVariable_PathAccept; method
+ to accept any path that the user supplies:
+
+ </para>
+
+ <scons_example name="PathAccept">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add(PathVariable('OUTPUT',
+ 'Path to output file or directory',
+ None,
+ PathVariable.PathAccept))
+ env = Environment(variables = vars,
+ CPPDEFINES={'OUTPUT' : '"$OUTPUT"'})
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ </scons_example>
+
+ </section>
+
+ <section>
+ <title>Enabled/Disabled Path Names: the &PackageVariable; Build Variable Function</title>
+
+ <para>
+
+ Sometimes you want to give users
+ even more control over a path name variable,
+ allowing them to explicitly enable or
+ disable the path name
+ by using <literal>yes</literal> or <literal>no</literal> keywords,
+ in addition to allow them
+ to supply an explicit path name.
+ &SCons; supports the &PackageVariable;
+ function to support this:
+
+ </para>
+
+ <scons_example name="PackageVariable">
+ <file name="SConstruct" printme="1">
+ vars = Variables('custom.py')
+ vars.Add(PackageVariable('PACKAGE',
+ 'Location package',
+ '__ROOT__/opt/location'))
+ env = Environment(variables = vars,
+ CPPDEFINES={'PACKAGE' : '"$PACKAGE"'})
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ <file name="__ROOT__/opt/location">
+ /opt/location
+ </file>
+ <file name="__ROOT__/usr/local/location">
+ /opt/location
+ </file>
+ </scons_example>
+
+ <para>
+
+ When the &SConscript; file uses the &PackageVariable; funciton,
+ user can now still use the default
+ or supply an overriding path name,
+ but can now explicitly set the
+ specified variable to a value
+ that indicates the package should be enabled
+ (in which case the default should be used)
+ or disabled:
+
+ </para>
+
+ <scons_output example="PackageVariable">
+ <scons_output_command>scons -Q foo.o</scons_output_command>
+ <scons_output_command>scons -Q PACKAGE=__ROOT__/usr/local/location foo.o</scons_output_command>
+ <scons_output_command>scons -Q PACKAGE=yes foo.o</scons_output_command>
+ <scons_output_command>scons -Q PACKAGE=no foo.o</scons_output_command>
+ </scons_output>
+
+ </section>
</section>
<section>
- <title>Single Value From a List: the &EnumOption; Build Option</title>
+ <title>Adding Multiple Command-Line Build Variables at Once</title>
<para>
- Suppose that we want a user to be able to
- set a &COLOR; option
- that selects a background color to be
- displayed by an application,
- but that we want to restrict the
- choices to a specific set of allowed colors.
- This can be set up quite easily
- using the &EnumOption;,
- which takes a list of &allowed_values
- in addition to the variable name,
- default value,
- and help text arguments:
+ Lastly, &SCons; provides a way to add
+ multiple build variables to a &Variables; object at once.
+ Instead of having to call the &Add; method
+ multiple times,
+ you can call the &AddVariables;
+ method with a list of build variables
+ to be added to the object.
+ Each build variable is specified
+ as either a tuple of arguments,
+ just like you'd pass to the &Add; method itself,
+ or as a call to one of the pre-defined
+ functions for pre-packaged command-line build variables.
+ in any order:
</para>
- <scons_example name="EnumOption">
+ <scons_example name="AddVariables_1">
<file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add(EnumOption('COLOR', 'Set background color', 'red',
- allowed_values=('red', 'green', 'blue')))
- env = Environment(options = opts,
- CPPDEFINES={'COLOR' : '"${COLOR}"'})
- env.Program('foo.c')
- </file>
- <file name="foo.c">
- foo.c
+ vars = Variables()
+ vars.AddVariables(
+ ('RELEASE', 'Set to 1 to build for release', 0),
+ ('CONFIG', 'Configuration file', '/etc/my_config'),
+ BoolVariable('warnings', 'compilation with -Wall and similiar', 1),
+ EnumVariable('debug', 'debug output and symbols', 'no',
+ allowed_values=('yes', 'no', 'full'),
+ map={}, ignorecase=0), # case sensitive
+ ListVariable('shared',
+ 'libraries to build as shared libraries',
+ 'all',
+ names = list_of_libs),
+ PackageVariable('x11',
+ 'use X11 installed here (yes = search some places)',
+ 'yes'),
+ PathVariable('qtdir', 'where the root of Qt is installed', qtdir),
+ )
</file>
</scons_example>
<para>
-
- The user can now explicity set the &COLOR; build option
- to any of the specified allowed values:
-
</para>
- <scons_output example="EnumOption">
- <scons_output_command>scons -Q COLOR=red foo.o</scons_output_command>
- <scons_output_command>scons -Q COLOR=blue foo.o</scons_output_command>
- <scons_output_command>scons -Q COLOR=green foo.o</scons_output_command>
- </scons_output>
+ </section>
+
+ <section>
+ <title>Handling Unknown Command-Line Build Variables: the &UnknownVariables; Function</title>
<para>
- But, almost more importantly,
- an attempt to set &COLOR;
- to a value that's not in the list
- generates an error message:
+ Users may, of course,
+ occasionally misspell variable names in their command-line settings.
+ &SCons; does not generate an error or warning
+ for any unknown variables the users specifies on the command line.
+ (This is in no small part because you may be
+ processing the arguments directly using the &ARGUMENTS; dictionary,
+ and therefore &SCons; can't know in the general case
+ whether a given "misspelled" variable is
+ really unknown and a potential problem,
+ or something that your &SConscript; file
+ will handle directly with some Python code.)
</para>
- <scons_output example="EnumOption">
- <scons_output_command>scons -Q COLOR=magenta foo.o</scons_output_command>
- </scons_output>
-
<para>
- The &EnumOption; function also supports a way
- to map alternate names to allowed values.
- Suppose, for example,
- that we want to allow the user
- to use the word <literal>navy</literal> as a synonym for
- <literal>blue</literal>.
- We do this by adding a ↦ dictionary
- that will map its key values
- to the desired legal value:
+ If, however, you're using a &Variables; object to
+ define a specific set of command-line build variables
+ that you expect users to be able to set,
+ you may want to provide an error
+ message or warning of your own
+ if the user supplies a variable setting
+ that is <emphasis>not</emphasis> among
+ the defined list of variable names known to the &Variables; object.
+ You can do this by calling the &UnknownVariables;
+ method of the &Variables; object:
</para>
- <scons_example name="EnumOption_map">
+ <scons_example name="UnknownVariables">
<file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add(EnumOption('COLOR', 'Set background color', 'red',
- allowed_values=('red', 'green', 'blue'),
- map={'navy':'blue'}))
- env = Environment(options = opts,
- CPPDEFINES={'COLOR' : '"${COLOR}"'})
+ vars = Variables(None)
+ vars.Add('RELEASE', 'Set to 1 to build for release', 0)
+ env = Environment(variables = vars,
+ CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
+ unknown = vars.UnknownVariables()
+ if unknown:
+ print "Unknown variables:", unknown.keys()
+ Exit(1)
env.Program('foo.c')
</file>
<file name="foo.c">
<para>
- As desired, the user can then use
- <literal>navy</literal> on the command line,
- and &SCons; will translate it into <literal>blue</literal>
- when it comes time to use the &COLOR;
- option to build a target:
+ The &UnknownVariables; method returns a dictionary
+ containing the keywords and values
+ of any variables the user specified on the command line
+ that are <emphasis>not</emphasis>
+ among the variables known to the &Variables; object
+ (from having been specified using
+ the &Variables; object's&Add; method).
+ In the examble above,
+ we check for whether the dictionary
+ returned by the &UnknownVariables; is non-empty,
+ and if so print the Python list
+ containing the names of the unknwown variables
+ and then call the &Exit; function
+ to terminate &SCons;:
</para>
- <scons_output example="EnumOption_map">
- <scons_output_command>scons -Q COLOR=navy foo.o</scons_output_command>
+ <scons_output example="UnknownVariables">
+ <scons_output_command>scons -Q NOT_KNOWN=foo</scons_output_command>
</scons_output>
<para>
- By default, when using the &EnumOption; function,
- arguments that differ
- from the legal values
- only in case
- are treated as illegal values:
+ Of course, you can process the items in the
+ dictionary returned by the &UnknownVariables; function
+ in any way appropriate to your bulid configuration,
+ including just printing a warning message
+ but not exiting,
+ logging an error somewhere,
+ etc.
</para>
- <scons_output example="EnumOption">
- <scons_output_command>scons -Q COLOR=Red foo.o</scons_output_command>
- <scons_output_command>scons -Q COLOR=BLUE foo.o</scons_output_command>
- <scons_output_command>scons -Q COLOR=nAvY foo.o</scons_output_command>
- </scons_output>
-
<para>
- The &EnumOption; function can take an additional
- &ignorecase; keyword argument that,
- when set to <literal>1</literal>,
- tells &SCons; to allow case differences
- when the values are specified:
+ Note that you must delay the call of &UnknownVariables;
+ until after you have applied the &Variables; object
+ to a construction environment
+ with the <literal>variables=</literal>
+ keyword argument of an &Environment; call.
</para>
- <scons_example name="EnumOption_ic1">
- <file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add(EnumOption('COLOR', 'Set background color', 'red',
- allowed_values=('red', 'green', 'blue'),
- map={'navy':'blue'},
- ignorecase=1))
- env = Environment(options = opts,
- CPPDEFINES={'COLOR' : '"${COLOR}"'})
- env.Program('foo.c')
- </file>
- <file name="foo.c">
- foo.c
- </file>
- </scons_example>
-
- <para>
+ </section>
- Which yields the output:
+ </section>
- </para>
+ <section id="sect-command-line-targets">
+ <title>Command-Line Targets</title>
- <scons_output example="EnumOption_ic1">
- <scons_output_command>scons -Q COLOR=Red foo.o</scons_output_command>
- <scons_output_command>scons -Q COLOR=BLUE foo.o</scons_output_command>
- <scons_output_command>scons -Q COLOR=nAvY foo.o</scons_output_command>
- <scons_output_command>scons -Q COLOR=green foo.o</scons_output_command>
- </scons_output>
+ <section>
+ <title>Fetching Command-Line Targets: the &COMMAND_LINE_TARGETS; Variable</title>
<para>
- Notice that an &ignorecase; value of <literal>1</literal>
- preserves the case-spelling that the user supplied.
- If you want &SCons; to translate the names
- into lower-case,
- regardless of the case used by the user,
- specify an &ignorecase; value of <literal>2</literal>:
+ &SCons; supports a &COMMAND_LINE_TARGETS; variable
+ that lets you fetch the list of targets that the
+ user specified on the command line.
+ You can use the targets to manipulate the
+ build in any way you wish.
+ As a simple example,
+ suppose that you want to print a reminder
+ to the user whenever a specific program is built.
+ You can do this by checking for the
+ target in the &COMMAND_LINE_TARGETS; list:
</para>
- <scons_example name="EnumOption_ic2">
+ <scons_example name="COMMAND_LINE_TARGETS">
<file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add(EnumOption('COLOR', 'Set background color', 'red',
- allowed_values=('red', 'green', 'blue'),
- map={'navy':'blue'},
- ignorecase=2))
- env = Environment(options = opts,
- CPPDEFINES={'COLOR' : '"${COLOR}"'})
- env.Program('foo.c')
+ if 'bar' in COMMAND_LINE_TARGETS:
+ print "Don't forget to copy `bar' to the archive!"
+ Default(Program('foo.c'))
+ Program('bar.c')
</file>
<file name="foo.c">
foo.c
</file>
+ <file name="bar.c">
+ foo.c
+ </file>
</scons_example>
<para>
- Now &SCons; will use values of
- <literal>red</literal>,
- <literal>green</literal> or
- <literal>blue</literal>
- regardless of how the user spells
- those values on the command line:
+ Then, running &SCons; with the default target
+ works as it always does,
+ but explicity specifying the &bar; target
+ on the command line generates the warning message:
</para>
- <scons_output example="EnumOption_ic2">
- <scons_output_command>scons -Q COLOR=Red foo.o</scons_output_command>
- <scons_output_command>scons -Q COLOR=nAvY foo.o</scons_output_command>
- <scons_output_command>scons -Q COLOR=GREEN foo.o</scons_output_command>
+ <scons_output example="COMMAND_LINE_TARGETS">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q bar</scons_output_command>
</scons_output>
+ <para>
+
+ Another practical use for the &COMMAND_LINE_TARGETS; variable
+ might be to speed up a build
+ by only reading certain subsidiary &SConscript;
+ files if a specific target is requested.
+
+ </para>
+
</section>
<section>
- <title>Multiple Values From a List: the &ListOption; Build Option</title>
+ <title>Controlling the Default Targets: the &Default; Function</title>
<para>
- Another way in which you might want to allow users
- to control build option is to
- specify a list of one or more legal values.
- &SCons; supports this through the &ListOption; function.
- If, for example, we want a user to be able to set a
- &COLORS; option to one or more of the legal list of values:
+ One of the most basic things you can control
+ is which targets &SCons; will build by default--that is,
+ when there are no targets specified on the command line.
+ As mentioned previously,
+ &SCons; will normally build every target
+ in or below the current directory
+ by default--that is, when you don't
+ explicitly specify one or more targets
+ on the command line.
+ Sometimes, however, you may want
+ to specify explicitly that only
+ certain programs, or programs in certain directories,
+ should be built by default.
+ You do this with the &Default; function:
</para>
- <scons_example name="ListOption">
- <file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add(ListOption('COLORS', 'List of colors', 0,
- ['red', 'green', 'blue']))
- env = Environment(options = opts,
- CPPDEFINES={'COLORS' : '"${COLORS}"'})
- env.Program('foo.c')
- </file>
- <file name="foo.c">
- foo.c
- </file>
+ <scons_example name="Default1">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ hello = env.Program('hello.c')
+ env.Program('goodbye.c')
+ Default(hello)
+ </file>
+ <file name="hello.c">
+ hello.c
+ </file>
+ <file name="goodbye.c">
+ goodbye.c
+ </file>
</scons_example>
<para>
- A user can now specify a comma-separated list
- of legal values,
- which will get translated into a space-separated
- list for passing to the any build commands:
+ This &SConstruct; file knows how to build two programs,
+ &hello; and &goodbye;,
+ but only builds the
+ &hello; program by default:
</para>
- <scons_output example="ListOption">
- <scons_output_command>scons -Q COLORS=red,blue foo.o</scons_output_command>
- <scons_output_command>scons -Q COLORS=blue,green,red foo.o</scons_output_command>
+ <scons_output example="Default1">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q goodbye</scons_output_command>
</scons_output>
<para>
- In addition, the &ListOption; function
- allows the user to specify explicit keywords of
- &all; or &none;
- to select all of the legal values,
- or none of them, respectively:
+ Note that, even when you use the &Default;
+ function in your &SConstruct; file,
+ you can still explicitly specify the current directory
+ (<literal>.</literal>) on the command line
+ to tell &SCons; to build
+ everything in (or below) the current directory:
</para>
- <scons_output example="ListOption">
- <scons_output_command>scons -Q COLORS=all foo.o</scons_output_command>
- <scons_output_command>scons -Q COLORS=none foo.o</scons_output_command>
+ <scons_output example="Default1">
+ <scons_output_command>scons -Q .</scons_output_command>
</scons_output>
<para>
- And, of course, an illegal value
- still generates an error message:
+ You can also call the &Default;
+ function more than once,
+ in which case each call
+ adds to the list of targets to be built by default:
</para>
- <scons_output example="ListOption">
- <scons_output_command>scons -Q COLORS=magenta foo.o</scons_output_command>
- </scons_output>
-
- </section>
-
- <section>
- <title>Path Names: the &PathOption; Build Option</title>
+ <scons_example name="Default2">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ prog1 = env.Program('prog1.c')
+ Default(prog1)
+ prog2 = env.Program('prog2.c')
+ prog3 = env.Program('prog3.c')
+ Default(prog3)
+ </file>
+ <file name="prog1.c">
+ prog1.c
+ </file>
+ <file name="prog2.c">
+ prog2.c
+ </file>
+ <file name="prog3.c">
+ prog3.c
+ </file>
+ </scons_example>
<para>
- &SCons; supports a &PathOption; function
- to make it easy to create a build option
- to control an expected path name.
- If, for example, you need to
- define a variable in the preprocessor
- that controls the location of a
- configuration file:
+ Or you can specify more than one target
+ in a single call to the &Default; function:
</para>
- <scons_example name="PathOption">
- <file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add(PathOption('CONFIG',
- 'Path to configuration file',
- '__ROOT__/etc/my_config'))
- env = Environment(options = opts,
- CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'})
- env.Program('foo.c')
- </file>
- <file name="foo.c">
- foo.c
- </file>
- <file name="__ROOT__/etc/my_config">
- /opt/location
- </file>
- <file name="__ROOT__/usr/local/etc/other_config">
- /opt/location
- </file>
- </scons_example>
+ <programlisting>
+ env = Environment()
+ prog1 = env.Program('prog1.c')
+ prog2 = env.Program('prog2.c')
+ prog3 = env.Program('prog3.c')
+ Default(prog1, prog3)
+ </programlisting>
<para>
- This then allows the user to
- override the &CONFIG; build option
- on the command line as necessary:
+ Either of these last two examples
+ will build only the
+ <application>prog1</application>
+ and
+ <application>prog3</application>
+ programs by default:
</para>
- <scons_output example="PathOption">
- <scons_output_command>scons -Q foo.o</scons_output_command>
- <scons_output_command>scons -Q CONFIG=__ROOT__/usr/local/etc/other_config foo.o</scons_output_command>
+ <scons_output example="Default2">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q .</scons_output_command>
</scons_output>
<para>
- By default, &PathOption; checks to make sure
- that the specified path exists and generates an error if it
- doesn't:
+ You can list a directory as
+ an argument to &Default;:
</para>
- <scons_output example="PathOption">
- <scons_output_command>scons -Q CONFIG=__ROOT__/does/not/exist foo.o</scons_output_command>
- </scons_output>
+ <scons_example name="Default3">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ env.Program(['prog1/main.c', 'prog1/foo.c'])
+ env.Program(['prog2/main.c', 'prog2/bar.c'])
+ Default('prog1')
+ </file>
+ <directory name="prog1"></directory>
+ <directory name="prog2"></directory>
+ <file name="prog1/main.c">
+ int main() { printf("prog1/main.c\n"); }
+ </file>
+ <file name="prog1/foo.c">
+ int foo() { printf("prog1/foo.c\n"); }
+ </file>
+ <file name="prog2/main.c">
+ int main() { printf("prog2/main.c\n"); }
+ </file>
+ <file name="prog2/bar.c">
+ int bar() { printf("prog2/bar.c\n"); }
+ </file>
+ </scons_example>
<para>
- &PathOption; provides a number of methods
- that you can use to change this behavior.
- If you want to ensure that any specified paths are,
- in fact, files and not directories,
- use the &PathOption_PathIsFile; method:
+ In which case only the target(s) in that
+ directory will be built by default:
</para>
- <scons_example name="PathIsFile">
- <file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add(PathOption('CONFIG',
- 'Path to configuration file',
- '__ROOT__/etc/my_config',
- PathOption.PathIsFile))
- env = Environment(options = opts,
- CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'})
- env.Program('foo.c')
- </file>
- <file name="foo.c">
- foo.c
- </file>
- <file name="__ROOT__/etc/my_config">
- /opt/location
- </file>
- </scons_example>
+ <scons_output example="Default3">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q .</scons_output_command>
+ </scons_output>
<para>
- Conversely, to ensure that any specified paths are
- directories and not files,
- use the &PathOption_PathIsDir; method:
+ Lastly, if for some reason you don't want
+ any targets built by default,
+ you can use the Python <literal>None</literal>
+ variable:
</para>
- <scons_example name="PathIsDir">
- <file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add(PathOption('DBDIR',
- 'Path to database directory',
- '__ROOT__/var/my_dbdir',
- PathOption.PathIsDir))
- env = Environment(options = opts,
- CPPDEFINES={'DBDIR' : '"$DBDIR"'})
- env.Program('foo.c')
- </file>
- <file name="foo.c">
- foo.c
- </file>
- <file name="__ROOT__/var/my_dbdir">
- /opt/location
- </file>
+ <scons_example name="Default4">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ prog1 = env.Program('prog1.c')
+ prog2 = env.Program('prog2.c')
+ Default(None)
+ </file>
+ <file name="prog1.c">
+ prog1.c
+ </file>
+ <file name="prog2.c">
+ prog2.c
+ </file>
</scons_example>
<para>
- If you want to make sure that any specified paths
- are directories,
- and you would like the directory created
- if it doesn't already exist,
- use the &PathOption_PathIsDirCreate; method:
+ Which would produce build output like:
</para>
- <scons_example name="PathIsDirCreate">
- <file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add(PathOption('DBDIR',
- 'Path to database directory',
- '__ROOT__/var/my_dbdir',
- PathOption.PathIsDirCreate))
- env = Environment(options = opts,
- CPPDEFINES={'DBDIR' : '"$DBDIR"'})
- env.Program('foo.c')
- </file>
- <file name="foo.c">
- foo.c
- </file>
- <file name="__ROOT__/var/my_dbdir">
- /opt/location
- </file>
- </scons_example>
+ <scons_output example="Default4">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q .</scons_output_command>
+ </scons_output>
+
+ <section>
+ <title>Fetching the List of Default Targets: the &DEFAULT_TARGETS; Variable</title>
+
+ <para>
+
+ &SCons; supports a &DEFAULT_TARGETS; variable
+ that lets you get at the current list of default targets.
+ The &DEFAULT_TARGETS variable has
+ two important differences from the &COMMAND_LINE_TARGETS; variable.
+ First, the &DEFAULT_TARGETS; variable is a list of
+ internal &SCons; nodes,
+ so you need to convert the list elements to strings
+ if you want to print them or look for a specific target name.
+ Fortunately, you can do this easily
+ by using the Python <function>map</function> function
+ to run the list through <function>str</function>:
+
+ </para>
+
+ <scons_example name="DEFAULT_TARGETS_1">
+ <file name="SConstruct" printme="1">
+ prog1 = Program('prog1.c')
+ Default(prog1)
+ print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS)
+ </file>
+ <file name="prog1.c">
+ prog1.c
+ </file>
+ </scons_example>
+
+ <para>
+
+ (Keep in mind that all of the manipulation of the
+ &DEFAULT_TARGETS; list takes place during the
+ first phase when &SCons; is reading up the &SConscript; files,
+ which is obvious if
+ we leave off the <literal>-Q</literal> flag when we run &SCons;:)
+
+ </para>
+
+ <scons_output example="DEFAULT_TARGETS_1">
+ <scons_output_command>scons</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ Second,
+ the contents of the &DEFAULT_TARGETS; list change
+ in response to calls to the &Default: function,
+ as you can see from the following &SConstruct; file:
+
+ </para>
+
+ <scons_example name="DEFAULT_TARGETS_2">
+ <file name="SConstruct" printme="1">
+ prog1 = Program('prog1.c')
+ Default(prog1)
+ print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS)
+ prog2 = Program('prog2.c')
+ Default(prog2)
+ print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS)
+ </file>
+ <file name="prog1.c">
+ prog1.c
+ </file>
+ <file name="prog2.c">
+ prog2.c
+ </file>
+ </scons_example>
+
+ <para>
+
+ Which yields the output:
+
+ </para>
+
+ <scons_output example="DEFAULT_TARGETS_2">
+ <scons_output_command>scons</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ In practice, this simply means that you
+ need to pay attention to the order in
+ which you call the &Default; function
+ and refer to the &DEFAULT_TARGETS; list,
+ to make sure that you don't examine the
+ list before you've added the default targets
+ you expect to find in it.
+
+ </para>
+
+ </section>
+
+ </section>
+
+ <section>
+ <title>Fetching the List of Build Targets, Regardless of Origin: the &BUILD_TARGETS; Variable</title>
<para>
- Lastly, if you don't care whether the path exists,
- is a file, or a directory,
- use the &PathOption_PathAccept; method
- to accept any path that the user supplies:
+ We've already been introduced to the
+ &COMMAND_LINE_TARGETS; variable,
+ which contains a list of targets specified on the command line,
+ and the &DEFAULT_TARGETS; variable,
+ which contains a list of targets specified
+ via calls to the &Default; method or function.
+ Sometimes, however,
+ you want a list of whatever targets
+ &SCons; will try to build,
+ regardless of whether the targets came from the
+ command line or a &Default; call.
+ You could code this up by hand, as follows:
</para>
- <scons_example name="PathAccept">
- <file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add(PathOption('OUTPUT',
- 'Path to output file or directory',
- None,
- PathOption.PathAccept))
- env = Environment(options = opts,
- CPPDEFINES={'OUTPUT' : '"$OUTPUT"'})
- env.Program('foo.c')
- </file>
- <file name="foo.c">
- foo.c
- </file>
- </scons_example>
+ <sconstruct>
+ if COMMAND_LINE_TARGETS:
+ targets = COMMAND_LINE_TARGETS
+ else:
+ targets = DEFAULT_TARGETS
+ </sconstruct>
- </section>
+ <para>
- <section>
- <title>Enabled/Disabled Path Names: the &PackageOption; Build Option</title>
+ &SCons;, however, provides a convenient
+ &BUILD_TARGETS; variable
+ that eliminates the need for this by-hand manipulation.
+ Essentially, the &BUILD_TARGETS; variable
+ contains a list of the command-line targets,
+ if any were specified,
+ and if no command-line targets were specified,
+ it contains a list of the targets specified
+ via the &Default; method or function.
+
+ </para>
<para>
- Sometimes you want to give users
- even more control over a path name variable,
- allowing them to explicitly enable or
- disable the path name
- by using <literal>yes</literal> or <literal>no</literal> keywords,
- in addition to allow them
- to supply an explicit path name.
- &SCons; supports the &PackageOption;
- function to support this:
+ Because &BUILD_TARGETS; may contain a list of &SCons; nodes,
+ you must convert the list elements to strings
+ if you want to print them or look for a specific target name,
+ just like the &DEFAULT_TARGETS; list:
</para>
- <scons_example name="PackageOption">
+ <scons_example name="BUILD_TARGETS_1">
<file name="SConstruct" printme="1">
- opts = Options('custom.py')
- opts.Add(PackageOption('PACKAGE',
- 'Location package',
- '__ROOT__/opt/location'))
- env = Environment(options = opts,
- CPPDEFINES={'PACKAGE' : '"$PACKAGE"'})
- env.Program('foo.c')
- </file>
- <file name="foo.c">
- foo.c
+ prog1 = Program('prog1.c')
+ Program('prog2.c')
+ Default(prog1)
+ print "BUILD_TARGETS is", map(str, BUILD_TARGETS)
</file>
- <file name="__ROOT__/opt/location">
- /opt/location
+ <file name="prog1.c">
+ prog1.c
</file>
- <file name="__ROOT__/usr/local/location">
- /opt/location
+ <file name="prog2.c">
+ prog2.c
</file>
</scons_example>
<para>
- When the &SConscript; file uses the &PackageOption; funciton,
- user can now still use the default
- or supply an overriding path name,
- but can now explicitly set the
- specified variable to a value
- that indicates the package should be enabled
- (in which case the default should be used)
- or disabled:
+ Notice how the value of &BUILD_TARGETS;
+ changes depending on whether a target is
+ specified on the command line:
</para>
- <scons_output example="PackageOption">
- <scons_output_command>scons -Q foo.o</scons_output_command>
- <scons_output_command>scons -Q PACKAGE=__ROOT__/usr/local/location foo.o</scons_output_command>
- <scons_output_command>scons -Q PACKAGE=yes foo.o</scons_output_command>
- <scons_output_command>scons -Q PACKAGE=no foo.o</scons_output_command>
+ <scons_output example="BUILD_TARGETS_1">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q prog2</scons_output_command>
+ <scons_output_command>scons -Q -c .</scons_output_command>
</scons_output>
</section>
</section>
-
- <section>
- <title>Adding Multiple Command-Line Build Options at Once</title>
-
- <para>
-
- Lastly, &SCons; provides a way to add
- multiple build options to an &Options object at once.
- Instead of having to call the &Add; method
- multiple times,
- you can call the &AddOptions;
- method with a list of build options
- to be added to the object.
- Each build option is specified
- as either a tuple of arguments,
- just like you'd pass to the &Add; method itself,
- or as a call to one of the canned
- functions for pre-packaged command-line build options.
- in any order:
-
- </para>
-
- <scons_example name="AddOptions_1">
- <file name="SConstruct" printme="1">
- opts = Options()
- opts.AddOptions(
- ('RELEASE', 'Set to 1 to build for release', 0),
- ('CONFIG', 'Configuration file', '/etc/my_config'),
- BoolOption('warnings', 'compilation with -Wall and similiar', 1),
- EnumOption('debug', 'debug output and symbols', 'no',
- allowed_values=('yes', 'no', 'full'),
- map={}, ignorecase=0), # case sensitive
- ListOption('shared',
- 'libraries to build as shared libraries',
- 'all',
- names = list_of_libs),
- PackageOption('x11',
- 'use X11 installed here (yes = search some places)',
- 'yes'),
- PathOption('qtdir', 'where the root of Qt is installed', qtdir),
- )
- </file>
- </scons_example>
-
- <para>
- </para>
-
- </section>
-
- <!--
-
- AddOption() function for things like - -prefix=, - -force
-
- -->
<para>
- &SCons; provides a number of ways that
- allow the writer of the &SConscript; files
- to give users a great deal of control over how to run the builds.
+ &SCons; provides a number of ways
+ for the writer of the &SConscript; files
+ to give the users who will run &SCons;
+ a great deal of control over the build execution.
+ The arguments that the user can specify on
+ the command line are broken down into three types:
</para>
- <section>
- <title>Not Having to Specify Command-Line Options Each Time: the &SCONSFLAGS; Environment Variable</title>
+ <variablelist>
- <para>
-
- Users may find themselves supplying
- the same command-line options every time
- they run &SCons;.
- For example, a user might find that it saves time
- to specify a value of <literal>-j 2</literal>
- to run the builds in parallel.
- To avoid having to type <literal>-j 2</literal> by hand
- every time,
- you can set the external environment variable
- &SCONSFLAGS; to a string containing
- command-line options that you want &SCons; to use.
-
- </para>
-
- <para>
-
- If, for example,
- you're using a POSIX shell that's
- compatible with the Bourne shell,
- and you always want &SCons; to use the
- <literal>-Q</literal> option,
- you can set the &SCONSFLAGS;
- environment as follows:
-
- </para>
-
-
-
- <screen>
- % <userinput>scons</userinput>
- scons: Reading SConscript files ...
- scons: done reading SConscript files.
- scons: Building targets ...
- ... [build output] ...
- scons: done building targets.
- % <userinput>export SCONSFLAGS="-Q"</userinput>
- % <userinput>scons</userinput>
- ... [build output] ...
- </screen>
-
- <para>
-
- Users of &csh;-style shells on POSIX systems
- can set the &SCONSFLAGS; environment as follows:
-
- </para>
-
- <screen>
- $ <userinput>setenv SCONSFLAGS "-Q"</userinput>
- </screen>
+ <varlistentry>
+ <term>Options</term>
+ <listitem>
<para>
- Windows users may typically want to set the
- &SCONSFLAGS; in the appropriate tab of the
- <literal>System Properties</literal> window.
+ Command-line options always begin with
+ one or two <literal>-</literal> (hyphen) characters.
+ &SCons; provides ways for you to examind
+ and set options values from within your &SConscript; files,
+ as well as the ability to define your own
+ custom options.
+ See <xref linkend="sect-command-line-options"></xref>, below.
</para>
+ </listitem>
+ </varlistentry>
- </section>
-
- <section>
- <title>Getting at Command-Line Targets</title>
+ <varlistentry>
+ <term>Variables</term>
+ <listitem>
<para>
- &SCons; supports a &COMMAND_LINE_TARGETS; variable
- that lets you get at the list of targets that the
- user specified on the command line.
- You can use the targets to manipulate the
- build in any way you wish.
- As a simple example,
- suppose that you want to print a reminder
- to the user whenever a specific program is built.
- You can do this by checking for the
- target in the &COMMAND_LINE_TARGETS; list:
-
- </para>
-
- <programlisting>
- if 'bar' in COMMAND_LINE_TARGETS:
- print "Don't forget to copy `bar' to the archive!"
- Default(Program('foo.c'))
- Program('bar.c')
- </programlisting>
-
- <para>
-
- Then, running &SCons; with the default target
- works as it always does,
- but explicity specifying the &bar; target
- on the command line generates the warning message:
+ Any command-line argument containing an <literal>=</literal>
+ (equal sign) is considered a variable setting with the form
+ <varname>variable</varname>=<varname>value</varname>
+ &SCons; provides direct access to
+ all of the command-line variable settings,
+ the ability to apply command-line variable settings
+ to construction environments,
+ and functions for configuring
+ specific types of variables
+ (Boolean values, path names, etc.)
+ with automatic validation of the user's specified values.
+ See <xref linkend="sect-command-line-variables"></xref>, below.
</para>
+ </listitem>
+ </varlistentry>
- <screen>
- % <userinput>scons -Q</userinput>
- cc -o foo.o -c foo.c
- cc -o foo foo.o
- % <userinput>scons -Q bar</userinput>
- Don't forget to copy `bar' to the archive!
- cc -o bar.o -c bar.c
- cc -o bar bar.o
- </screen>
+ <varlistentry>
+ <term>Targets</term>
+ <listitem>
<para>
- Another practical use for the &COMMAND_LINE_TARGETS; variable
- might be to speed up a build
- by only reading certain subsidiary &SConscript;
- files if a specific target is requested.
+ Any command-line argument that is not an option
+ or a variable setting
+ (does not begin with a hyphen
+ and does not contain an equal sign)
+ is considered a target that the user
+ (presumably) wants &SCons; to build.
+ A list of Node objects representing
+ the target or targets to build.
+ &SCons; provides access to the list of specified targets,
+ as well as ways to set the default list of targets
+ from within the &SConscript; files.
+ See <xref linkend="sect-command-line-targets"></xref>, below.
</para>
+ </listitem>
+ </varlistentry>
- </section>
+ </variablelist>
- <section>
- <title>Controlling the Default Targets</title>
+ <section id="sect-command-line-options">
+ <title>Command-Line Options</title>
<para>
- One of the most basic things you can control
- is which targets &SCons; will build by default--that is,
- when there are no targets specified on the command line.
- As mentioned previously,
- &SCons; will normally build every target
- in or below the current directory
- by default--that is, when you don't
- explicitly specify one or more targets
- on the command line.
- Sometimes, however, you may want
- to specify explicitly that only
- certain programs, or programs in certain directories,
- should be built by default.
- You do this with the &Default; function:
+ &SCons; has many <emphasis>command-line options</emphasis>
+ that control its behavior.
+ A &SCons; <emphasis>command-line option</emphasis>
+ always begins with one or two <literal>-</literal> (hyphen)
+ characters.
</para>
- <programlisting>
- env = Environment()
- hello = env.Program('hello.c')
- env.Program('goodbye.c')
- Default(hello)
- </programlisting>
-
- <para>
-
- This &SConstruct; file knows how to build two programs,
- &hello; and &goodbye;,
- but only builds the
- &hello; program by default:
+ <section>
+ <title>Not Having to Specify Command-Line Options Each Time: the &SCONSFLAGS; Environment Variable</title>
- </para>
+ <para>
- <screen>
- % <userinput>scons -Q</userinput>
- cc -o hello.o -c hello.c
- cc -o hello hello.o
- % <userinput>scons -Q</userinput>
- scons: `hello' is up to date.
- % <userinput>scons -Q goodbye</userinput>
- cc -o goodbye.o -c goodbye.c
- cc -o goodbye goodbye.o
- </screen>
+ Users may find themselves supplying
+ the same command-line options every time
+ they run &SCons;.
+ For example, you might find it saves time
+ to specify a value of <literal>-j 2</literal>
+ to have &SCons; run up to two build commands in parallel.
+ To avoid having to type <literal>-j 2</literal> by hand
+ every time,
+ you can set the external environment variable
+ &SCONSFLAGS; to a string containing
+ command-line options that you want &SCons; to use.
- <para>
+ </para>
- Note that, even when you use the &Default;
- function in your &SConstruct; file,
- you can still explicitly specify the current directory
- (<literal>.</literal>) on the command line
- to tell &SCons; to build
- everything in (or below) the current directory:
+ <para>
- </para>
+ If, for example,
+ you're using a POSIX shell that's
+ compatible with the Bourne shell,
+ and you always want &SCons; to use the
+ <literal>-Q</literal> option,
+ you can set the &SCONSFLAGS;
+ environment as follows:
- <screen>
- % <userinput>scons -Q .</userinput>
- cc -o goodbye.o -c goodbye.c
- cc -o goodbye goodbye.o
- cc -o hello.o -c hello.c
- cc -o hello hello.o
- </screen>
+ </para>
- <para>
+
- You can also call the &Default;
- function more than once,
- in which case each call
- adds to the list of targets to be built by default:
+ <screen>
+ % <userinput>scons</userinput>
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ ... [build output] ...
+ scons: done building targets.
+ % <userinput>export SCONSFLAGS="-Q"</userinput>
+ % <userinput>scons</userinput>
+ ... [build output] ...
+ </screen>
- </para>
+ <para>
- <programlisting>
- env = Environment()
- prog1 = env.Program('prog1.c')
- Default(prog1)
- prog2 = env.Program('prog2.c')
- prog3 = env.Program('prog3.c')
- Default(prog3)
- </programlisting>
+ Users of &csh;-style shells on POSIX systems
+ can set the &SCONSFLAGS; environment as follows:
- <para>
+ </para>
- Or you can specify more than one target
- in a single call to the &Default; function:
+ <screen>
+ $ <userinput>setenv SCONSFLAGS "-Q"</userinput>
+ </screen>
- </para>
+ <para>
- <programlisting>
- env = Environment()
- prog1 = env.Program('prog1.c')
- prog2 = env.Program('prog2.c')
- prog3 = env.Program('prog3.c')
- Default(prog1, prog3)
- </programlisting>
+ Windows users may typically want to set the
+ &SCONSFLAGS; in the appropriate tab of the
+ <literal>System Properties</literal> window.
- <para>
+ </para>
- Either of these last two examples
- will build only the
- <application>prog1</application>
- and
- <application>prog3</application>
- programs by default:
+ </section>
- </para>
+ <section>
+ <title>Getting Values Set by Command-Line Options: the &GetOption; Function</title>
- <screen>
- % <userinput>scons -Q</userinput>
- cc -o prog1.o -c prog1.c
- cc -o prog1 prog1.o
- cc -o prog3.o -c prog3.c
- cc -o prog3 prog3.o
- % <userinput>scons -Q .</userinput>
- cc -o prog2.o -c prog2.c
- cc -o prog2 prog2.o
- </screen>
+ <para>
- <para>
+ &SCons; provides the &GetOption; function
+ to get the values set by the various command-line options.
+ One common use of this is to check whether or not
+ the <literal>-h</literal> or <literal>--help</literal> option
+ has been specified.
+ Normally, &SCons; does not print its help text
+ until after it has read all of the &SConscript; files,
+ because it's possible that help text has been added
+ by some subsidiary &SConscript; file deep in the
+ source tree hierarchy.
+ Of course, reading all of the &SConscript; files
+ takes extra time.
- You can list a directory as
- an argument to &Default;:
+ </para>
- </para>
+ <para>
- <programlisting>
- env = Environment()
- env.Program(['prog1/main.c', 'prog1/foo.c'])
- env.Program(['prog2/main.c', 'prog2/bar.c'])
- Default('prog1')
- </programlisting>
+ If you know that your configuration does not define
+ any additional help text in subsidiary &SConscript; files,
+ you can speed up the command-line help available to users
+ by using the &GetOption; function to load the
+ subsidiary &SConscript; files only if the
+ the user has <emphasis>not</emphasis> specified
+ the <literal>-h</literal> or <literal>--help</literal> option,
+ like so:
- <para>
+ </para>
- In which case only the target(s) in that
- directory will be built by default:
+ <programlisting></programlisting>
- </para>
+ <para>
- <screen>
- % <userinput>scons -Q</userinput>
- cc -o prog1/foo.o -c prog1/foo.c
- cc -o prog1/main.o -c prog1/main.c
- cc -o prog1/main prog1/main.o prog1/foo.o
- % <userinput>scons -Q</userinput>
- scons: `prog1' is up to date.
- % <userinput>scons -Q .</userinput>
- cc -o prog2/bar.o -c prog2/bar.c
- cc -o prog2/main.o -c prog2/main.c
- cc -o prog2/main prog2/main.o prog2/bar.o
- </screen>
+ In general, the string that you pass to the
+ &GetOption; function to fetch the value of a command-line
+ option setting is the same as the "most common" long option name
+ (beginning with two hyphen characters),
+ although there are some exceptions.
+ The list of &SCons; command-line options
+ and the &GetOption; strings for fetching them,
+ are available in the
+ <xref linkend="sect-command-line-option-strings"></xref> section,
+ below.
- <para>
+ </para>
- Lastly, if for some reason you don't want
- any targets built by default,
- you can use the Python <literal>None</literal>
- variable:
+ </section>
- </para>
+ <section>
+ <title>Setting Values of Command-Line Options: the &SetOption; Function</title>
- <programlisting>
- env = Environment()
- prog1 = env.Program('prog1.c')
- prog2 = env.Program('prog2.c')
- Default(None)
- </programlisting>
+ <para>
- <para>
+ You can also set the values of &SCons;
+ command-line options from within the &SConscript; files
+ by using the &SetOption; function.
+ The strings that you use to set the values of &SCons;
+ command-line options are available in the
+ <xref linkend="sect-command-line-option-strings"></xref> section,
+ below.
- Which would produce build output like:
+ </para>
- </para>
+ <para>
- <screen>
- % <userinput>scons -Q</userinput>
- scons: *** No targets specified and no Default() targets found. Stop.
- % <userinput>scons -Q .</userinput>
- cc -o prog1.o -c prog1.c
- cc -o prog1 prog1.o
- cc -o prog2.o -c prog2.c
- cc -o prog2 prog2.o
- </screen>
+ One use of the &SetOption; function is to
+ specify a value for the <literal>-j</literal>
+ or <literal>--jobs</literal> option,
+ so that users get the improved performance
+ of a parallel build without having to specify the option by hand.
+ A complicating factor is that a good value
+ for the <literal>-j</literal> option is
+ somewhat system-dependent.
+ One rough guideline is that the more processors
+ your system has,
+ the higher you want to set the
+ <literal>-j</literal> value,
+ in order to take advantage of the number of CPUs.
- <section>
- <title>Getting at the List of Default Targets</title>
+ </para>
<para>
- &SCons; supports a &DEFAULT_TARGETS; variable
- that lets you get at the current list of default targets.
- The &DEFAULT_TARGETS variable has
- two important differences from the &COMMAND_LINE_TARGETS; variable.
- First, the &DEFAULT_TARGETS; variable is a list of
- internal &SCons; nodes,
- so you need to convert the list elements to strings
- if you want to print them or look for a specific target name.
- Fortunately, you can do this easily
- by using the Python <function>map</function> function
- to run the list through <function>str</function>:
+ For example, suppose the administrators
+ of your development systems
+ have standardized on setting a
+ <varname>NUM_CPU</varname> environment variable
+ to the number of processors on each system.
+ A little bit of Python code
+ to access the environment variable
+ and the &SetOption; function
+ provide the right level of flexibility:
</para>
<programlisting>
- prog1 = Program('prog1.c')
- Default(prog1)
- print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS)
+ import os
+ num_cpu = int(os.environ.get('NUM_CPU', 2))
+ SetOption('num_jobs', num_cpu)
+ print "running with -j", GetOption('num_jobs')
</programlisting>
<para>
- (Keep in mind that all of the manipulation of the
- &DEFAULT_TARGETS; list takes place during the
- first phase when &SCons; is reading up the &SConscript; files,
- which is obvious if
- we leave off the <literal>-Q</literal> flag when we run &SCons;:)
+ The above snippet of code
+ sets the value of the <literal>--jobs</literal> option
+ to the value specified in the
+ <varname>$NUM_CPU</varname> environment variable.
+ (This is one of the exception cases
+ where the string is spelled differently from
+ the from command-line option.
+ The string for fetching or setting the <literal>--jobs</literal>
+ value is <literal>num_jobs</literal>
+ for historical reasons.)
+ The code in this example prints the <literal>num_jobs</literal>
+ value for illustrative purposes.
+ It uses a default value of <literal>2</literal>
+ to provide some minimal parallelism even on
+ single-processor systems:
</para>
<screen>
- % <userinput>scons</userinput>
- scons: Reading SConscript files ...
- DEFAULT_TARGETS is ['prog1']
- scons: done reading SConscript files.
- scons: Building targets ...
- cc -o prog1.o -c prog1.c
- cc -o prog1 prog1.o
- scons: done building targets.
+ % <userinput>scons -Q</userinput>
+ running with -j 2
+ scons: `.' is up to date.
</screen>
<para>
- Second,
- the contents of the &DEFAULT_TARGETS; list change
- in response to calls to the &Default;: function,
- as you can see from the following &SConstruct; file:
+ But if the <varname>$NUM_CPU</varname>
+ environment variable is set,
+ then we use that for the default number of jobs:
</para>
- <programlisting>
- prog1 = Program('prog1.c')
- Default(prog1)
- print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS)
- prog2 = Program('prog2.c')
- Default(prog2)
- print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS)
- </programlisting>
+ <screen>
+ % <userinput>export NUM_CPU="4"</userinput>
+ % <userinput>scons -Q</userinput>
+ running with -j 4
+ scons: `.' is up to date.
+ </screen>
<para>
- Which yields the output:
+ But any explicit
+ <literal>-j</literal> or <literal>--jobs</literal>
+ value the user specifies an the command line is used first,
+ regardless of whether or not
+ the <varname>$NUM_CPU</varname> environment
+ variable is set:
</para>
<screen>
- % <userinput>scons</userinput>
- scons: Reading SConscript files ...
- DEFAULT_TARGETS is now ['prog1']
- DEFAULT_TARGETS is now ['prog1', 'prog2']
- scons: done reading SConscript files.
- scons: Building targets ...
- cc -o prog1.o -c prog1.c
- cc -o prog1 prog1.o
- cc -o prog2.o -c prog2.c
- cc -o prog2 prog2.o
- scons: done building targets.
+ % <userinput>scons -Q -j 7</userinput>
+ running with -j 7
+ scons: `.' is up to date.
+ % <userinput>export NUM_CPU="4"</userinput>
+ % <userinput>scons -Q -j 3</userinput>
+ running with -j 3
+ scons: `.' is up to date.
</screen>
+ </section>
+
+ <section id="sect-command-line-option-strings">
+ <title>Strings for Getting or Setting Values of &SCons; Command-Line Options</title>
+
<para>
- In practice, this simply means that you
- need to pay attention to the order in
- which you call the &Default; function
- and refer to the &DEFAULT_TARGETS; list,
- to make sure that you don't examine the
- list before you've added the default targets
- you expect to find in it.
+ The strings that you can pass to the &GetOption;
+ and &SetOption; functions usually correspond to the
+ first long-form option name
+ (beginning with two hyphen characters: <literal>--</literal>),
+ after replacing any remaining hyphen characters
+ with underscores.
</para>
+ <para>
+
+ The full list of strings and the variables they
+ correspond to is as follows:
+
+ </para>
+
+ <informaltable>
+ <tgroup cols="2" align="left">
+
+ <thead>
+
+ <row>
+ <entry>String for &GetOption; and &SetOption;</entry>
+ <entry>Command-Line Option(s)</entry>
+ </row>
+
+ </thead>
+
+ <tbody>
+
+ <row>
+ <entry><literal>cache_debug</literal></entry>
+ <entry><option>--cache-debug</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>cache_disable</literal></entry>
+ <entry><option>--cache-disable</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>cache_force</literal></entry>
+ <entry><option>--cache-force</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>cache_show</literal></entry>
+ <entry><option>--cache-show</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>clean</literal></entry>
+ <entry><option>-c</option>,
+ <option>--clean</option>,
+ <option>--remove</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>config</literal></entry>
+ <entry><option>--config</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>directory</literal></entry>
+ <entry><option>-C</option>,
+ <option>--directory</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>diskcheck</literal></entry>
+ <entry><option>--diskcheck</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>duplicate</literal></entry>
+ <entry><option>--duplicate</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>file</literal></entry>
+ <entry><option>-f</option>,
+ <option>--file</option>,
+ <option>--makefile </option>,
+ <option>--sconstruct</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>help</literal></entry>
+ <entry><option>-h</option>,
+ <option>--help</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>ignore_errors</literal></entry>
+ <entry><option>--ignore-errors</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>implicit_cache</literal></entry>
+ <entry><option>--implicit-cache</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>implicit_deps_changed</literal></entry>
+ <entry><option>--implicit-deps-changed</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>implicit_deps_unchanged</literal></entry>
+ <entry><option>--implicit-deps-unchanged</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>interactive</literal></entry>
+ <entry><option>--interact</option>,
+ <option>--interactive</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>keep_going</literal></entry>
+ <entry><option>-k</option>,
+ <option>--keep-going</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>max_drift</literal></entry>
+ <entry><option>--max-drift</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>no_exec</literal></entry>
+ <entry><option>-n</option>,
+ <option>--no-exec</option>,
+ <option>--just-print</option>,
+ <option>--dry-run</option>,
+ <option>--recon</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>no_site_dir</literal></entry>
+ <entry><option>--no-site-dir</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>num_jobs</literal></entry>
+ <entry><option>-j</option>,
+ <option>--jobs</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>profile_file</literal></entry>
+ <entry><option>--profile</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>question</literal></entry>
+ <entry><option>-q</option>,
+ <option>--question</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>random</literal></entry>
+ <entry><option>--random</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>repository</literal></entry>
+ <entry><option>-Y</option>,
+ <option>--repository</option>,
+ <option>--srcdir</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>silent</literal></entry>
+ <entry><option>-s</option>,
+ <option>--silent</option>,
+ <option>--quiet</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>site_dir</literal></entry>
+ <entry><option>--site-dir</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>stack_size</literal></entry>
+ <entry><option>--stack-size</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>taskmastertrace_file</literal></entry>
+ <entry><option>--taskmastertrace</option></entry>
+ </row>
+
+ <row>
+ <entry><literal>warn</literal></entry>
+ <entry><option>--warn</option> <option>--warning</option></entry>
+ </row>
+
+ </tbody>
+
+ </tgroup>
+ </informaltable>
+
</section>
- </section>
+ <section>
+ <title>Adding Custom Command-Line Options: the &AddOption; Function</title>
- <section>
- <title>Getting at the List of Build Targets, Regardless of Origin</title>
+ <para>
- <para>
+ &SCons; also allows you to define your own
+ command-line options with the &AddOption; function.
+ The &AddOption; function takes the same arguments
+ as the <function>optparse.add_option</function> function
+ from the standard Python library.
+ <footnote>
+ <para>
+ The &AddOption; function is,
+ in fact, implemented using a subclass
+ of the <classname>optparse.OptionParser</classname>.
+ </para>
+ </footnote>
+ Once you have added a custom command-line option
+ with the &AddOption; function,
+ the value of the option (if any) is immediately available
+ using the standard &GetOption; function.
+ (The value can also be set using &SetOption;,
+ although that's not very useful in practice
+ because a default value can be specified in
+ directly in the &AddOption; call.)
- We've already been introduced to the
- &COMMAND_LINE_TARGETS; variable,
- which contains a list of targets specified on the command line,
- and the &DEFAULT_TARGETS; variable,
- which contains a list of targets specified
- via calls to the &Default; method or function.
- Sometimes, however,
- you want a list of whatever targets
- &SCons; will try to build,
- regardless of whether the targets came from the
- command line or a &Default; call.
- You could code this up by hand, as follows:
+ </para>
- </para>
+ <para>
- <programlisting>
- if COMMAND_LINE_TARGETS:
- targets = COMMAND_LINE_TARGETS
- else:
- targets = DEFAULT_TARGETS
- </programlisting>
+ One useful example of using this functionality
+ is to provide a <option>--prefix</option> for users:
- <para>
+ </para>
- &SCons;, however, provides a convenient
- &BUILD_TARGETS; variable
- that eliminates the need for this by-hand manipulation.
- Essentially, the &BUILD_TARGETS; variable
- contains a list of the command-line targets,
- if any were specified,
- and if no command-line targets were specified,
- it contains a list of the targets specified
- via the &Default; method or function.
+ <programlisting>
+ AddOption('--prefix',
+ dest='prefix',
+ type='string',
+ nargs=1,
+ action='store',
+ metavar='DIR',
+ help='installation prefix')
+
+ env = Environment(PREFIX = GetOption('prefix'))
+
+ installed_foo = env.Install('$PREFIX/usr/bin', 'foo.in')
+ Default(installed_foo)
+ </programlisting>
- </para>
+ <para>
- <para>
+ The above code uses the &GetOption; function
+ to set the <varname>$PREFIX</varname>
+ construction variable to any
+ value that the user specifies with a command-line
+ option of <literal>--prefix</literal>.
+ Because <varname>$PREFIX</varname>
+ will expand to a null string if it's not initialized,
+ running &SCons; without the
+ option of <literal>--prefix</literal>
+ will install the file in the
+ <filename>/usr/bin/</filename> directory:
- Because &BUILD_TARGETS; may contain a list of &SCons; nodes,
- you must convert the list elements to strings
- if you want to print them or look for a specific target name,
- just like the &DEFAULT_TARGETS; list:
+ </para>
- </para>
+ <screen>
+ % <userinput>scons -Q -n</userinput>
+ Install file: "foo.in" as "/usr/bin/foo.in"
+ </screen>
- <programlisting>
- prog1 = Program('prog1.c')
- Program('prog2.c')
- Default(prog1)
- print "BUILD_TARGETS is", map(str, BUILD_TARGETS)
- </programlisting>
+ <para>
- <para>
+ But specifying <literal>--prefix=/tmp/install</literal>
+ on the command line causes the file to be installed in the
+ <filename>/tmp/install/usr/bin/</filename> directory:
- Notice how the value of &BUILD_TARGETS;
- changes depending on whether a target is
- specified on the command line:
+ </para>
- </para>
+ <screen>
+ % <userinput>scons -Q -n --prefix=/tmp/install</userinput>
+ Install file: "foo.in" as "/tmp/install/usr/bin/foo.in"
+ </screen>
- <screen>
- % <userinput>scons -Q</userinput>
- BUILD_TARGETS is ['prog1']
- cc -o prog1.o -c prog1.c
- cc -o prog1 prog1.o
- % <userinput>scons -Q prog2</userinput>
- BUILD_TARGETS is ['prog2']
- cc -o prog2.o -c prog2.c
- cc -o prog2 prog2.o
- % <userinput>scons -Q -c .</userinput>
- BUILD_TARGETS is ['.']
- Removed prog1.o
- Removed prog1
- Removed prog2.o
- Removed prog2
- </screen>
+ </section>
</section>
- <section>
- <title>Command-Line <varname>variable</varname>=<varname>value</varname> Build Options</title>
+ <section id="sect-command-line-variables">
+ <title>Command-Line <varname>variable</varname>=<varname>value</varname> Build Variables</title>
<para>
to specifications on the command line.
(Note that unless you want to require
that users <emphasis>always</emphasis>
- specify an option,
+ specify a variable,
you probably want to use
the Python
<literal>ARGUMENTS.get()</literal> function,
</para>
- </section>
-
- <section>
- <title>Controlling Command-Line Build Options</title>
-
<para>
- Being able to use a command-line build option like
- <literal>debug=1</literal> is handy,
- but it can be a chore to write specific Python code
- to recognize each such option
- and apply the values to a construction variable.
- To help with this,
- &SCons; supports a class to
- define such build options easily,
- and a mechanism to apply the
- build options to a construction environment.
- This allows you to control how the build options affect
- construction environments.
+ The &ARGUMENTS; dictionary has two minor drawbacks.
+ First, because it is a dictionary,
+ it can only store one value for each specified keyword,
+ and thus only "remembers" the last setting
+ for each keyword on the command line.
+ This makes the &ARGUMENTS; dictionary
+ inappropriate if users should be able to
+ specify multiple values
+ on the command line for a given keyword.
+ Second, it does not preserve
+ the order in which the variable settings
+ were specified,
+ which is a problem if
+ you want the configuration to
+ behave differently in response
+ to the order in which the build
+ variable settings were specified on the command line.
</para>
<para>
- For example, suppose that you want users to set
- a &RELEASE; construction variable on the
- command line whenever the time comes to build
- a program for release,
- and that the value of this variable
- should be added to the command line
- with the appropriate <literal>-D</literal> option
- (or other command line option)
- to pass the value to the C compiler.
- Here's how you might do that by setting
- the appropriate value in a dictionary for the
- &cv-link-CPPDEFINES; construction variable:
+ To accomodate these requirements,
+ &SCons; provides an &ARGLIST; variable
+ that gives you direct access to
+ <varname>variable</varname>=<varname>value</varname>
+ settings on the command line,
+ in the exact order they were specified,
+ and without removing any duplicate settings.
+ Each element in the &ARGLIST; variable
+ is itself a two-element list
+ containing the keyword and the value
+ of the setting,
+ and you must loop through,
+ or otherwise select from,
+ the elements of &ARGLIST; to
+ process the specific settings you want
+ in whatever way is appropriate for your configuration.
+ For example,
+ the following code to let the user
+ add to the &CPPDEFINES; construction variable
+ by specifying multiple
+ <varname>define=</varname>
+ settings on the command line:
</para>
<programlisting>
- opts = Options()
- opts.Add('RELEASE', 'Set to 1 to build for release', 0)
- env = Environment(options = opts,
- CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
- env.Program(['foo.c', 'bar.c'])
+ cppdefines = []
+ for key, value in ARGLIST:
+ if key == 'define':
+ cppdefines.append(value)
+ env = Environment(CPPDEFINES = cppdefines)
+ env.Object('prog.c')
</programlisting>
<para>
- This &SConstruct; file first creates an
- &Options; object
- (the <literal>opts = Options()</literal> call),
- and then uses the object's &Add;
- method to indicate that the &RELEASE;
- option can be set on the command line,
- and that it's default value will be <literal>0</literal>
- (the third argument to the &Add; method).
- The second argument is a line of help text;
- we'll learn how to use it in the next section.
-
- </para>
-
- <para>
-
- We then pass the created &Options;
- object as an &options; keyword argument
- to the &Environment; call
- used to create the construction environment.
- This then allows a user to set the
- &RELEASE; build option on the command line
- and have the variable show up in
- the command line used to build each object from
- a C source file:
+ Yields the followig output:
</para>
<screen>
- % <userinput>scons -Q RELEASE=1</userinput>
- cc -o bar.o -c -DRELEASE_BUILD=1 bar.c
- cc -o foo.o -c -DRELEASE_BUILD=1 foo.c
- cc -o foo foo.o bar.o
+ % <userinput>scons -Q define=FOO</userinput>
+ cc -o prog.o -c -DFOO prog.c
+ % <userinput>scons -Q define=FOO define=BAR</userinput>
+ cc -o prog.o -c -DFOO -DBAR prog.c
</screen>
- </section>
-
- <section>
- <title>Providing Help for Command-Line Build Options</title>
-
<para>
- To make command-line build options most useful,
- you ideally want to provide
- some help text that will describe
- the available options
- when the user runs <literal>scons -h</literal>.
- You could write this text by hand,
- but &SCons; provides an easier way.
- &Options; objects support a
- &GenerateHelpText; method
- that will, as its name indicates,
- generate text that describes
- the various options that
- have been added to it.
- You then pass the output from this method to
- the &Help; function:
+ Note that the &ARGLIST; and &ARGUMENTS;
+ variables do not interfere with each other,
+ but merely provide slightly different views
+ into how the user specified
+ <varname>variable</varname>=<varname>value</varname>
+ settings on the command line.
+ You can use both variables in the same
+ &SCons; configuration.
+ In general, the &ARGUMENTS; dictionary
+ is more convenient to use,
+ (since you can just fetch variable
+ settings through a dictionary access),
+ and the &ARGLIST; list
+ is more flexible
+ (since you can examine the
+ specific order in which
+ the user's command-line variabe settings).
</para>
- <programlisting>
- opts = Options('custom.py')
- opts.Add('RELEASE', 'Set to 1 to build for release', 0)
- env = Environment(options = opts)
- Help(opts.GenerateHelpText(env))
- </programlisting>
-
- <para>
-
- &SCons; will now display some useful text
- when the <literal>-h</literal> option is used:
-
- </para>
+ <section>
+ <title>Controlling Command-Line Build Variables</title>
- <screen>
- % <userinput>scons -Q -h</userinput>
-
- RELEASE: Set to 1 to build for release
- default: 0
- actual: 0
-
- Use scons -H for help about command-line options.
- </screen>
+ <para>
- <para>
+ Being able to use a command-line build variable like
+ <literal>debug=1</literal> is handy,
+ but it can be a chore to write specific Python code
+ to recognize each such variable,
+ check for errors and provide appropriate messages,
+ and apply the values to a construction variable.
+ To help with this,
+ &SCons; supports a class to
+ define such build variables easily,
+ and a mechanism to apply the
+ build variables to a construction environment.
+ This allows you to control how the build variables affect
+ construction environments.
- Notice that the help output shows the default value,
- and the current actual value of the build option.
+ </para>
- </para>
+ <para>
- </section>
+ For example, suppose that you want users to set
+ a &RELEASE; construction variable on the
+ command line whenever the time comes to build
+ a program for release,
+ and that the value of this variable
+ should be added to the command line
+ with the appropriate <literal>-D</literal> option
+ (or other command line option)
+ to pass the value to the C compiler.
+ Here's how you might do that by setting
+ the appropriate value in a dictionary for the
+ &cv-link-CPPDEFINES; construction variable:
- <section>
- <title>Reading Build Options From a File</title>
+ </para>
- <para>
+ <programlisting>
+ vars = Variables()
+ vars.Add('RELEASE', 'Set to 1 to build for release', 0)
+ env = Environment(variables = vars,
+ CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
+ env.Program(['foo.c', 'bar.c'])
+ </programlisting>
- Being able to use a command-line build option like
- <literal>debug=1</literal> is handy,
- but it can be a chore to write specific Python code
- to recognize each such option
- and apply the values to a construction variable.
- To help with this,
- &SCons; supports a class to
- define such build options easily
- and to read build option values from a file.
- This allows you to control how the build options affect
- construction environments.
- The way you do this is by specifying
- a file name when you call &Options;,
- like &custom_py; in the following example:
+ <para>
- </para>
+ This &SConstruct; file first creates a &Variables; object
+ (the <literal>vars = Variables()</literal> call),
+ and then uses the object's &Add;
+ method to indicate that the &RELEASE;
+ variable can be set on the command line,
+ and that its default value will be <literal>0</literal>
+ (the third argument to the &Add; method).
+ The second argument is a line of help text;
+ we'll learn how to use it in the next section.
- <programlisting>
- opts = Options('custom.py')
- opts.Add('RELEASE', 'Set to 1 to build for release', 0)
- env = Environment(options = opts,
- CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
- env.Program(['foo.c', 'bar.c'])
- Help(opts.GenerateHelpText(env))
- </programlisting>
+ </para>
- <para>
+ <para>
- This then allows us to control the &RELEASE;
- variable by setting it in the &custom_py; file:
+ We then pass the created &Variables;
+ object as a &variables; keyword argument
+ to the &Environment; call
+ used to create the construction environment.
+ This then allows a user to set the
+ &RELEASE; build variable on the command line
+ and have the variable show up in
+ the command line used to build each object from
+ a C source file:
- </para>
+ </para>
- <programlisting>
- RELEASE = 1
- </programlisting>
+ <screen>
+ % <userinput>scons -Q RELEASE=1</userinput>
+ cc -o bar.o -c -DRELEASE_BUILD=1 bar.c
+ cc -o foo.o -c -DRELEASE_BUILD=1 foo.c
+ cc -o foo foo.o bar.o
+ </screen>
- <para>
+ <para>
- Note that this file is actually executed
- like a Python script.
- Now when we run &SCons;:
+ NOTE: Before &SCons; release 0.98.1, these build variables
+ were known as "command-line build options."
+ The class was actually named the &Options; class,
+ and in the sections below,
+ the various functions were named
+ &BoolOption;, &EnumOption;, &ListOption;,
+ &PathOption;, &PackageOption; and &AddOptions;.
+ These older names still work,
+ and you may encounter them in older
+ &SConscript; fles,
+ but their use is discouraged
+ and will be officially deprecated some day.
- </para>
+ </para>
- <screen>
- % <userinput>scons -Q</userinput>
- cc -o bar.o -c -DRELEASE_BUILD=1 bar.c
- cc -o foo.o -c -DRELEASE_BUILD=1 foo.c
- cc -o foo foo.o bar.o
- </screen>
+ </section>
- <para>
+ <section>
+ <title>Providing Help for Command-Line Build Variables</title>
- And if we change the contents of &custom_py; to:
+ <para>
- </para>
+ To make command-line build variables most useful,
+ you ideally want to provide
+ some help text that will describe
+ the available variables
+ when the user runs <literal>scons -h</literal>.
+ You could write this text by hand,
+ but &SCons; provides an easier way.
+ &Variables; objects support a
+ &GenerateHelpText; method
+ that will, as its name suggests,
+ generate text that describes
+ the various variables that
+ have been added to it.
+ You then pass the output from this method to
+ the &Help; function:
- <programlisting>
- RELEASE = 0
- </programlisting>
+ </para>
- <para>
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add('RELEASE', 'Set to 1 to build for release', 0)
+ env = Environment(variables = vars)
+ Help(vars.GenerateHelpText(env))
+ </programlisting>
- The object files are rebuilt appropriately
- with the new option:
+ <para>
- </para>
+ &SCons; will now display some useful text
+ when the <literal>-h</literal> option is used:
- <screen>
- % <userinput>scons -Q</userinput>
- cc -o bar.o -c -DRELEASE_BUILD=0 bar.c
- cc -o foo.o -c -DRELEASE_BUILD=0 foo.c
- cc -o foo foo.o bar.o
- </screen>
+ </para>
- </section>
+ <screen>
+ % <userinput>scons -Q -h</userinput>
+
+ RELEASE: Set to 1 to build for release
+ default: 0
+ actual: 0
+
+ Use scons -H for help about command-line options.
+ </screen>
- <section>
- <title>Canned Build Options</title>
+ <para>
- <para>
+ Notice that the help output shows the default value,
+ and the current actual value of the build variable.
- &SCons; provides a number of functions
- that provide ready-made behaviors
- for various types of command-line build options.
+ </para>
- </para>
+ </section>
<section>
- <title>True/False Values: the &BoolOption; Build Option</title>
+ <title>Reading Build Variables From a File</title>
<para>
- It's often handy to be able to specify an
- option that controls a simple Boolean variable
- with a &true; or &false; value.
- It would be even more handy to accomodate
- users who have different preferences for how to represent
- &true; or &false; values.
- The &BoolOption; function
- makes it easy to accomodate a variety of
- common values that represent
- &true; or &false;.
+ Giving the user a way to specify the
+ value of a build variable on the command line
+ is useful,
+ but can still be tedious
+ if users must specify the variable
+ every time they run &SCons;.
+ We can let users provide customized build variable settings
+ in a local file by providing a
+ file name when we create the
+ &Variables; object:
</para>
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add('RELEASE', 'Set to 1 to build for release', 0)
+ env = Environment(variables = vars,
+ CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
+ env.Program(['foo.c', 'bar.c'])
+ Help(vars.GenerateHelpText(env))
+ </programlisting>
+
<para>
- The &BoolOption; function takes three arguments:
- the name of the build option,
- the default value of the build option,
- and the help string for the option.
- It then returns appropriate information for
- passing to the &Add; method of an &Options; object, like so:
+ This then allows the user to control the &RELEASE;
+ variable by setting it in the &custom_py; file:
</para>
<programlisting>
- opts = Options('custom.py')
- opts.Add(BoolOption('RELEASE', 'Set to build for release', 0))
- env = Environment(options = opts,
- CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
- env.Program('foo.c')
- </programlisting>
+ RELEASE = 1
+ </programlisting>
<para>
- With this build option,
- the &RELEASE; variable can now be enabled by
- setting it to the value <literal>yes</literal>
- or <literal>t</literal>:
+ Note that this file is actually executed
+ like a Python script.
+ Now when we run &SCons;:
</para>
<screen>
- % <userinput>scons -Q RELEASE=yes foo.o</userinput>
- cc -o foo.o -c -DRELEASE_BUILD=True foo.c
- </screen>
-
- <screen>
- % <userinput>scons -Q RELEASE=t foo.o</userinput>
- cc -o foo.o -c -DRELEASE_BUILD=True foo.c
+ % <userinput>scons -Q</userinput>
+ cc -o bar.o -c -DRELEASE_BUILD=1 bar.c
+ cc -o foo.o -c -DRELEASE_BUILD=1 foo.c
+ cc -o foo foo.o bar.o
</screen>
<para>
- Other values that equate to &true; include
- <literal>y</literal>,
- <literal>1</literal>,
- <literal>on</literal>
- and
- <literal>all</literal>.
+ And if we change the contents of &custom_py; to:
</para>
+ <programlisting>
+ RELEASE = 0
+ </programlisting>
+
<para>
- Conversely, &RELEASE; may now be given a &false;
- value by setting it to
- <literal>no</literal>
- or
- <literal>f</literal>:
+ The object files are rebuilt appropriately
+ with the new variable:
</para>
<screen>
- % <userinput>scons -Q RELEASE=no foo.o</userinput>
- cc -o foo.o -c -DRELEASE_BUILD=False foo.c
+ % <userinput>scons -Q</userinput>
+ cc -o bar.o -c -DRELEASE_BUILD=0 bar.c
+ cc -o foo.o -c -DRELEASE_BUILD=0 foo.c
+ cc -o foo foo.o bar.o
</screen>
- <screen>
- % <userinput>scons -Q RELEASE=f foo.o</userinput>
- cc -o foo.o -c -DRELEASE_BUILD=False foo.c
- </screen>
+ </section>
+
+ <section>
+ <title>Pre-Defined Build Variable Functions</title>
<para>
- Other values that equate to &false; include
- <literal>n</literal>,
- <literal>0</literal>,
- <literal>off</literal>
- and
- <literal>none</literal>.
+ &SCons; provides a number of functions
+ that provide ready-made behaviors
+ for various types of command-line build variables.
</para>
- <para>
+ <section>
+ <title>True/False Values: the &BoolVariable; Build Variable Function</title>
- Lastly, if a user tries to specify
- any other value,
- &SCons; supplies an appropriate error message:
+ <para>
- </para>
+ It's often handy to be able to specify a
+ variable that controls a simple Boolean variable
+ with a &true; or &false; value.
+ It would be even more handy to accomodate
+ users who have different preferences for how to represent
+ &true; or &false; values.
+ The &BoolVariable; function
+ makes it easy to accomodate these
+ common representations of
+ &true; or &false;.
- <screen>
- % <userinput>scons -Q RELEASE=bad_value foo.o</userinput>
-
- scons: *** Error converting option: RELEASE
- Invalid value for boolean option: bad_value
- File "/home/my/project/SConstruct", line 4, in <module>
- </screen>
+ </para>
+
+ <para>
+
+ The &BoolVariable; function takes three arguments:
+ the name of the build variable,
+ the default value of the build variable,
+ and the help string for the variable.
+ It then returns appropriate information for
+ passing to the &Add; method of a &Variables; object, like so:
+
+ </para>
+
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add(BoolVariable('RELEASE', 'Set to build for release', 0))
+ env = Environment(variables = vars,
+ CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+ With this build variable,
+ the &RELEASE; variable can now be enabled by
+ setting it to the value <literal>yes</literal>
+ or <literal>t</literal>:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q RELEASE=yes foo.o</userinput>
+ cc -o foo.o -c -DRELEASE_BUILD=True foo.c
+ </screen>
+
+ <screen>
+ % <userinput>scons -Q RELEASE=t foo.o</userinput>
+ cc -o foo.o -c -DRELEASE_BUILD=True foo.c
+ </screen>
+
+ <para>
+
+ Other values that equate to &true; include
+ <literal>y</literal>,
+ <literal>1</literal>,
+ <literal>on</literal>
+ and
+ <literal>all</literal>.
+
+ </para>
+
+ <para>
+
+ Conversely, &RELEASE; may now be given a &false;
+ value by setting it to
+ <literal>no</literal>
+ or
+ <literal>f</literal>:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q RELEASE=no foo.o</userinput>
+ cc -o foo.o -c -DRELEASE_BUILD=False foo.c
+ </screen>
+
+ <screen>
+ % <userinput>scons -Q RELEASE=f foo.o</userinput>
+ cc -o foo.o -c -DRELEASE_BUILD=False foo.c
+ </screen>
+
+ <para>
+
+ Other values that equate to &false; include
+ <literal>n</literal>,
+ <literal>0</literal>,
+ <literal>off</literal>
+ and
+ <literal>none</literal>.
+
+ </para>
+
+ <para>
+
+ Lastly, if a user tries to specify
+ any other value,
+ &SCons; supplies an appropriate error message:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q RELEASE=bad_value foo.o</userinput>
+
+ scons: *** Error converting option: RELEASE
+ Invalid value for boolean option: bad_value
+ File "/home/my/project/SConstruct", line 4, in <module>
+ </screen>
+
+ </section>
+
+ <section>
+ <title>Single Value From a List: the &EnumVariable; Build Variable Function</title>
+
+ <para>
+
+ Suppose that we want a user to be able to
+ set a &COLOR; variable
+ that selects a background color to be
+ displayed by an application,
+ but that we want to restrict the
+ choices to a specific set of allowed colors.
+ This can be set up quite easily
+ using the &EnumVariable;,
+ which takes a list of &allowed_values
+ in addition to the variable name,
+ default value,
+ and help text arguments:
+
+ </para>
+
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add(EnumVariable('COLOR', 'Set background color', 'red',
+ allowed_values=('red', 'green', 'blue')))
+ env = Environment(variables = vars,
+ CPPDEFINES={'COLOR' : '"${COLOR}"'})
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+ The user can now explicity set the &COLOR; build variable
+ to any of the specified allowed values:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q COLOR=red foo.o</userinput>
+ cc -o foo.o -c -DCOLOR="red" foo.c
+ % <userinput>scons -Q COLOR=blue foo.o</userinput>
+ cc -o foo.o -c -DCOLOR="blue" foo.c
+ % <userinput>scons -Q COLOR=green foo.o</userinput>
+ cc -o foo.o -c -DCOLOR="green" foo.c
+ </screen>
+
+ <para>
+
+ But, almost more importantly,
+ an attempt to set &COLOR;
+ to a value that's not in the list
+ generates an error message:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q COLOR=magenta foo.o</userinput>
+
+ scons: *** Invalid value for option COLOR: magenta
+ File "/home/my/project/SConstruct", line 5, in <module>
+ </screen>
+
+ <para>
+
+ The &EnumVariable; function also supports a way
+ to map alternate names to allowed values.
+ Suppose, for example,
+ that we want to allow the user
+ to use the word <literal>navy</literal> as a synonym for
+ <literal>blue</literal>.
+ We do this by adding a ↦ dictionary
+ that will map its key values
+ to the desired legal value:
+
+ </para>
+
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add(EnumVariable('COLOR', 'Set background color', 'red',
+ allowed_values=('red', 'green', 'blue'),
+ map={'navy':'blue'}))
+ env = Environment(variables = vars,
+ CPPDEFINES={'COLOR' : '"${COLOR}"'})
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+ As desired, the user can then use
+ <literal>navy</literal> on the command line,
+ and &SCons; will translate it into <literal>blue</literal>
+ when it comes time to use the &COLOR;
+ variable to build a target:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q COLOR=navy foo.o</userinput>
+ cc -o foo.o -c -DCOLOR="blue" foo.c
+ </screen>
+
+ <para>
+
+ By default, when using the &EnumVariable; function,
+ arguments that differ
+ from the legal values
+ only in case
+ are treated as illegal values:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q COLOR=Red foo.o</userinput>
+
+ scons: *** Invalid value for option COLOR: Red
+ File "/home/my/project/SConstruct", line 5, in <module>
+ % <userinput>scons -Q COLOR=BLUE foo.o</userinput>
+
+ scons: *** Invalid value for option COLOR: BLUE
+ File "/home/my/project/SConstruct", line 5, in <module>
+ % <userinput>scons -Q COLOR=nAvY foo.o</userinput>
+
+ scons: *** Invalid value for option COLOR: nAvY
+ File "/home/my/project/SConstruct", line 5, in <module>
+ </screen>
+
+ <para>
+
+ The &EnumVariable; function can take an additional
+ &ignorecase; keyword argument that,
+ when set to <literal>1</literal>,
+ tells &SCons; to allow case differences
+ when the values are specified:
+
+ </para>
+
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add(EnumVariable('COLOR', 'Set background color', 'red',
+ allowed_values=('red', 'green', 'blue'),
+ map={'navy':'blue'},
+ ignorecase=1))
+ env = Environment(variables = vars,
+ CPPDEFINES={'COLOR' : '"${COLOR}"'})
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+ Which yields the output:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q COLOR=Red foo.o</userinput>
+ cc -o foo.o -c -DCOLOR="Red" foo.c
+ % <userinput>scons -Q COLOR=BLUE foo.o</userinput>
+ cc -o foo.o -c -DCOLOR="BLUE" foo.c
+ % <userinput>scons -Q COLOR=nAvY foo.o</userinput>
+ cc -o foo.o -c -DCOLOR="blue" foo.c
+ % <userinput>scons -Q COLOR=green foo.o</userinput>
+ cc -o foo.o -c -DCOLOR="green" foo.c
+ </screen>
+
+ <para>
+
+ Notice that an &ignorecase; value of <literal>1</literal>
+ preserves the case-spelling that the user supplied.
+ If you want &SCons; to translate the names
+ into lower-case,
+ regardless of the case used by the user,
+ specify an &ignorecase; value of <literal>2</literal>:
+
+ </para>
+
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add(EnumVariable('COLOR', 'Set background color', 'red',
+ allowed_values=('red', 'green', 'blue'),
+ map={'navy':'blue'},
+ ignorecase=2))
+ env = Environment(variables = vars,
+ CPPDEFINES={'COLOR' : '"${COLOR}"'})
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+ Now &SCons; will use values of
+ <literal>red</literal>,
+ <literal>green</literal> or
+ <literal>blue</literal>
+ regardless of how the user spells
+ those values on the command line:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q COLOR=Red foo.o</userinput>
+ cc -o foo.o -c -DCOLOR="red" foo.c
+ % <userinput>scons -Q COLOR=nAvY foo.o</userinput>
+ cc -o foo.o -c -DCOLOR="blue" foo.c
+ % <userinput>scons -Q COLOR=GREEN foo.o</userinput>
+ cc -o foo.o -c -DCOLOR="green" foo.c
+ </screen>
+
+ </section>
+
+ <section>
+ <title>Multiple Values From a List: the &ListVariable; Build Variable Function</title>
+
+ <para>
+
+ Another way in which you might want to allow users
+ to control a build variable is to
+ specify a list of one or more legal values.
+ &SCons; supports this through the &ListVariable; function.
+ If, for example, we want a user to be able to set a
+ &COLORS; variable to one or more of the legal list of values:
+
+ </para>
+
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add(ListVariable('COLORS', 'List of colors', 0,
+ ['red', 'green', 'blue']))
+ env = Environment(variables = vars,
+ CPPDEFINES={'COLORS' : '"${COLORS}"'})
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+ A user can now specify a comma-separated list
+ of legal values,
+ which will get translated into a space-separated
+ list for passing to the any build commands:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q COLORS=red,blue foo.o</userinput>
+ cc -o foo.o -c -DCOLORS="red blue" foo.c
+ % <userinput>scons -Q COLORS=blue,green,red foo.o</userinput>
+ cc -o foo.o -c -DCOLORS="blue green red" foo.c
+ </screen>
+
+ <para>
+
+ In addition, the &ListVariable; function
+ allows the user to specify explicit keywords of
+ &all; or &none;
+ to select all of the legal values,
+ or none of them, respectively:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q COLORS=all foo.o</userinput>
+ cc -o foo.o -c -DCOLORS="red green blue" foo.c
+ % <userinput>scons -Q COLORS=none foo.o</userinput>
+ cc -o foo.o -c -DCOLORS="" foo.c
+ </screen>
+
+ <para>
+
+ And, of course, an illegal value
+ still generates an error message:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q COLORS=magenta foo.o</userinput>
+
+ scons: *** Error converting option: COLORS
+ Invalid value(s) for option: magenta
+ File "/home/my/project/SConstruct", line 5, in <module>
+ </screen>
+
+ </section>
+
+ <section>
+ <title>Path Names: the &PathVariable; Build Variable Function</title>
+
+ <para>
+
+ &SCons; supports a &PathVariable; function
+ to make it easy to create a build variable
+ to control an expected path name.
+ If, for example, you need to
+ define a variable in the preprocessor
+ that controls the location of a
+ configuration file:
+
+ </para>
+
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add(PathVariable('CONFIG',
+ 'Path to configuration file',
+ '/etc/my_config'))
+ env = Environment(variables = vars,
+ CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'})
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+ This then allows the user to
+ override the &CONFIG; build variable
+ on the command line as necessary:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q foo.o</userinput>
+ cc -o foo.o -c -DCONFIG_FILE="/etc/my_config" foo.c
+ % <userinput>scons -Q CONFIG=/usr/local/etc/other_config foo.o</userinput>
+ scons: `foo.o' is up to date.
+ </screen>
+
+ <para>
+
+ By default, &PathVariable; checks to make sure
+ that the specified path exists and generates an error if it
+ doesn't:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q CONFIG=/does/not/exist foo.o</userinput>
+
+ scons: *** Path for option CONFIG does not exist: /does/not/exist
+ File "/home/my/project/SConstruct", line 6, in <module>
+ </screen>
+
+ <para>
+
+ &PathVariable; provides a number of methods
+ that you can use to change this behavior.
+ If you want to ensure that any specified paths are,
+ in fact, files and not directories,
+ use the &PathVariable_PathIsFile; method:
+
+ </para>
+
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add(PathVariable('CONFIG',
+ 'Path to configuration file',
+ '/etc/my_config',
+ PathVariable.PathIsFile))
+ env = Environment(variables = vars,
+ CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'})
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+ Conversely, to ensure that any specified paths are
+ directories and not files,
+ use the &PathVariable_PathIsDir; method:
+
+ </para>
+
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add(PathVariable('DBDIR',
+ 'Path to database directory',
+ '/var/my_dbdir',
+ PathVariable.PathIsDir))
+ env = Environment(variables = vars,
+ CPPDEFINES={'DBDIR' : '"$DBDIR"'})
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+ If you want to make sure that any specified paths
+ are directories,
+ and you would like the directory created
+ if it doesn't already exist,
+ use the &PathVariable_PathIsDirCreate; method:
+
+ </para>
+
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add(PathVariable('DBDIR',
+ 'Path to database directory',
+ '/var/my_dbdir',
+ PathVariable.PathIsDirCreate))
+ env = Environment(variables = vars,
+ CPPDEFINES={'DBDIR' : '"$DBDIR"'})
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+ Lastly, if you don't care whether the path exists,
+ is a file, or a directory,
+ use the &PathVariable_PathAccept; method
+ to accept any path that the user supplies:
+
+ </para>
+
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add(PathVariable('OUTPUT',
+ 'Path to output file or directory',
+ None,
+ PathVariable.PathAccept))
+ env = Environment(variables = vars,
+ CPPDEFINES={'OUTPUT' : '"$OUTPUT"'})
+ env.Program('foo.c')
+ </programlisting>
+
+ </section>
+
+ <section>
+ <title>Enabled/Disabled Path Names: the &PackageVariable; Build Variable Function</title>
+
+ <para>
+
+ Sometimes you want to give users
+ even more control over a path name variable,
+ allowing them to explicitly enable or
+ disable the path name
+ by using <literal>yes</literal> or <literal>no</literal> keywords,
+ in addition to allow them
+ to supply an explicit path name.
+ &SCons; supports the &PackageVariable;
+ function to support this:
+
+ </para>
+
+ <programlisting>
+ vars = Variables('custom.py')
+ vars.Add(PackageVariable('PACKAGE',
+ 'Location package',
+ '/opt/location'))
+ env = Environment(variables = vars,
+ CPPDEFINES={'PACKAGE' : '"$PACKAGE"'})
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+ When the &SConscript; file uses the &PackageVariable; funciton,
+ user can now still use the default
+ or supply an overriding path name,
+ but can now explicitly set the
+ specified variable to a value
+ that indicates the package should be enabled
+ (in which case the default should be used)
+ or disabled:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q foo.o</userinput>
+ cc -o foo.o -c -DPACKAGE="/opt/location" foo.c
+ % <userinput>scons -Q PACKAGE=/usr/local/location foo.o</userinput>
+ cc -o foo.o -c -DPACKAGE="/usr/local/location" foo.c
+ % <userinput>scons -Q PACKAGE=yes foo.o</userinput>
+ cc -o foo.o -c -DPACKAGE="True" foo.c
+ % <userinput>scons -Q PACKAGE=no foo.o</userinput>
+ cc -o foo.o -c -DPACKAGE="False" foo.c
+ </screen>
+
+ </section>
</section>
<section>
- <title>Single Value From a List: the &EnumOption; Build Option</title>
+ <title>Adding Multiple Command-Line Build Variables at Once</title>
<para>
- Suppose that we want a user to be able to
- set a &COLOR; option
- that selects a background color to be
- displayed by an application,
- but that we want to restrict the
- choices to a specific set of allowed colors.
- This can be set up quite easily
- using the &EnumOption;,
- which takes a list of &allowed_values
- in addition to the variable name,
- default value,
- and help text arguments:
+ Lastly, &SCons; provides a way to add
+ multiple build variables to a &Variables; object at once.
+ Instead of having to call the &Add; method
+ multiple times,
+ you can call the &AddVariables;
+ method with a list of build variables
+ to be added to the object.
+ Each build variable is specified
+ as either a tuple of arguments,
+ just like you'd pass to the &Add; method itself,
+ or as a call to one of the pre-defined
+ functions for pre-packaged command-line build variables.
+ in any order:
</para>
<programlisting>
- opts = Options('custom.py')
- opts.Add(EnumOption('COLOR', 'Set background color', 'red',
- allowed_values=('red', 'green', 'blue')))
- env = Environment(options = opts,
- CPPDEFINES={'COLOR' : '"${COLOR}"'})
- env.Program('foo.c')
+ vars = Variables()
+ vars.AddVariables(
+ ('RELEASE', 'Set to 1 to build for release', 0),
+ ('CONFIG', 'Configuration file', '/etc/my_config'),
+ BoolVariable('warnings', 'compilation with -Wall and similiar', 1),
+ EnumVariable('debug', 'debug output and symbols', 'no',
+ allowed_values=('yes', 'no', 'full'),
+ map={}, ignorecase=0), # case sensitive
+ ListVariable('shared',
+ 'libraries to build as shared libraries',
+ 'all',
+ names = list_of_libs),
+ PackageVariable('x11',
+ 'use X11 installed here (yes = search some places)',
+ 'yes'),
+ PathVariable('qtdir', 'where the root of Qt is installed', qtdir),
+ )
</programlisting>
<para>
-
- The user can now explicity set the &COLOR; build option
- to any of the specified allowed values:
-
</para>
- <screen>
- % <userinput>scons -Q COLOR=red foo.o</userinput>
- cc -o foo.o -c -DCOLOR="red" foo.c
- % <userinput>scons -Q COLOR=blue foo.o</userinput>
- cc -o foo.o -c -DCOLOR="blue" foo.c
- % <userinput>scons -Q COLOR=green foo.o</userinput>
- cc -o foo.o -c -DCOLOR="green" foo.c
- </screen>
+ </section>
+
+ <section>
+ <title>Handling Unknown Command-Line Build Variables: the &UnknownVariables; Function</title>
<para>
- But, almost more importantly,
- an attempt to set &COLOR;
- to a value that's not in the list
- generates an error message:
+ Users may, of course,
+ occasionally misspell variable names in their command-line settings.
+ &SCons; does not generate an error or warning
+ for any unknown variables the users specifies on the command line.
+ (This is in no small part because you may be
+ processing the arguments directly using the &ARGUMENTS; dictionary,
+ and therefore &SCons; can't know in the general case
+ whether a given "misspelled" variable is
+ really unknown and a potential problem,
+ or something that your &SConscript; file
+ will handle directly with some Python code.)
</para>
- <screen>
- % <userinput>scons -Q COLOR=magenta foo.o</userinput>
-
- scons: *** Invalid value for option COLOR: magenta
- File "/home/my/project/SConstruct", line 5, in <module>
- </screen>
-
<para>
- The &EnumOption; function also supports a way
- to map alternate names to allowed values.
- Suppose, for example,
- that we want to allow the user
- to use the word <literal>navy</literal> as a synonym for
- <literal>blue</literal>.
- We do this by adding a ↦ dictionary
- that will map its key values
- to the desired legal value:
+ If, however, you're using a &Variables; object to
+ define a specific set of command-line build variables
+ that you expect users to be able to set,
+ you may want to provide an error
+ message or warning of your own
+ if the user supplies a variable setting
+ that is <emphasis>not</emphasis> among
+ the defined list of variable names known to the &Variables; object.
+ You can do this by calling the &UnknownVariables;
+ method of the &Variables; object:
</para>
<programlisting>
- opts = Options('custom.py')
- opts.Add(EnumOption('COLOR', 'Set background color', 'red',
- allowed_values=('red', 'green', 'blue'),
- map={'navy':'blue'}))
- env = Environment(options = opts,
- CPPDEFINES={'COLOR' : '"${COLOR}"'})
+ vars = Variables(None)
+ vars.Add('RELEASE', 'Set to 1 to build for release', 0)
+ env = Environment(variables = vars,
+ CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'})
+ unknown = vars.UnknownVariables()
+ if unknown:
+ print "Unknown variables:", unknown.keys()
+ Exit(1)
env.Program('foo.c')
</programlisting>
<para>
- As desired, the user can then use
- <literal>navy</literal> on the command line,
- and &SCons; will translate it into <literal>blue</literal>
- when it comes time to use the &COLOR;
- option to build a target:
+ The &UnknownVariables; method returns a dictionary
+ containing the keywords and values
+ of any variables the user specified on the command line
+ that are <emphasis>not</emphasis>
+ among the variables known to the &Variables; object
+ (from having been specified using
+ the &Variables; object's&Add; method).
+ In the examble above,
+ we check for whether the dictionary
+ returned by the &UnknownVariables; is non-empty,
+ and if so print the Python list
+ containing the names of the unknwown variables
+ and then call the &Exit; function
+ to terminate &SCons;:
</para>
<screen>
- % <userinput>scons -Q COLOR=navy foo.o</userinput>
- cc -o foo.o -c -DCOLOR="blue" foo.c
+ % <userinput>scons -Q NOT_KNOWN=foo</userinput>
+ Unknown variables: ['NOT_KNOWN']
</screen>
<para>
- By default, when using the &EnumOption; function,
- arguments that differ
- from the legal values
- only in case
- are treated as illegal values:
+ Of course, you can process the items in the
+ dictionary returned by the &UnknownVariables; function
+ in any way appropriate to your bulid configuration,
+ including just printing a warning message
+ but not exiting,
+ logging an error somewhere,
+ etc.
</para>
- <screen>
- % <userinput>scons -Q COLOR=Red foo.o</userinput>
-
- scons: *** Invalid value for option COLOR: Red
- File "/home/my/project/SConstruct", line 5, in <module>
- % <userinput>scons -Q COLOR=BLUE foo.o</userinput>
-
- scons: *** Invalid value for option COLOR: BLUE
- File "/home/my/project/SConstruct", line 5, in <module>
- % <userinput>scons -Q COLOR=nAvY foo.o</userinput>
-
- scons: *** Invalid value for option COLOR: nAvY
- File "/home/my/project/SConstruct", line 5, in <module>
- </screen>
-
<para>
- The &EnumOption; function can take an additional
- &ignorecase; keyword argument that,
- when set to <literal>1</literal>,
- tells &SCons; to allow case differences
- when the values are specified:
+ Note that you must delay the call of &UnknownVariables;
+ until after you have applied the &Variables; object
+ to a construction environment
+ with the <literal>variables=</literal>
+ keyword argument of an &Environment; call.
</para>
- <programlisting>
- opts = Options('custom.py')
- opts.Add(EnumOption('COLOR', 'Set background color', 'red',
- allowed_values=('red', 'green', 'blue'),
- map={'navy':'blue'},
- ignorecase=1))
- env = Environment(options = opts,
- CPPDEFINES={'COLOR' : '"${COLOR}"'})
- env.Program('foo.c')
- </programlisting>
-
- <para>
+ </section>
- Which yields the output:
+ </section>
- </para>
+ <section id="sect-command-line-targets">
+ <title>Command-Line Targets</title>
- <screen>
- % <userinput>scons -Q COLOR=Red foo.o</userinput>
- cc -o foo.o -c -DCOLOR="Red" foo.c
- % <userinput>scons -Q COLOR=BLUE foo.o</userinput>
- cc -o foo.o -c -DCOLOR="BLUE" foo.c
- % <userinput>scons -Q COLOR=nAvY foo.o</userinput>
- cc -o foo.o -c -DCOLOR="blue" foo.c
- % <userinput>scons -Q COLOR=green foo.o</userinput>
- cc -o foo.o -c -DCOLOR="green" foo.c
- </screen>
+ <section>
+ <title>Fetching Command-Line Targets: the &COMMAND_LINE_TARGETS; Variable</title>
<para>
- Notice that an &ignorecase; value of <literal>1</literal>
- preserves the case-spelling that the user supplied.
- If you want &SCons; to translate the names
- into lower-case,
- regardless of the case used by the user,
- specify an &ignorecase; value of <literal>2</literal>:
+ &SCons; supports a &COMMAND_LINE_TARGETS; variable
+ that lets you fetch the list of targets that the
+ user specified on the command line.
+ You can use the targets to manipulate the
+ build in any way you wish.
+ As a simple example,
+ suppose that you want to print a reminder
+ to the user whenever a specific program is built.
+ You can do this by checking for the
+ target in the &COMMAND_LINE_TARGETS; list:
</para>
<programlisting>
- opts = Options('custom.py')
- opts.Add(EnumOption('COLOR', 'Set background color', 'red',
- allowed_values=('red', 'green', 'blue'),
- map={'navy':'blue'},
- ignorecase=2))
- env = Environment(options = opts,
- CPPDEFINES={'COLOR' : '"${COLOR}"'})
- env.Program('foo.c')
+ if 'bar' in COMMAND_LINE_TARGETS:
+ print "Don't forget to copy `bar' to the archive!"
+ Default(Program('foo.c'))
+ Program('bar.c')
</programlisting>
<para>
- Now &SCons; will use values of
- <literal>red</literal>,
- <literal>green</literal> or
- <literal>blue</literal>
- regardless of how the user spells
- those values on the command line:
+ Then, running &SCons; with the default target
+ works as it always does,
+ but explicity specifying the &bar; target
+ on the command line generates the warning message:
</para>
<screen>
- % <userinput>scons -Q COLOR=Red foo.o</userinput>
- cc -o foo.o -c -DCOLOR="red" foo.c
- % <userinput>scons -Q COLOR=nAvY foo.o</userinput>
- cc -o foo.o -c -DCOLOR="blue" foo.c
- % <userinput>scons -Q COLOR=GREEN foo.o</userinput>
- cc -o foo.o -c -DCOLOR="green" foo.c
+ % <userinput>scons -Q</userinput>
+ cc -o foo.o -c foo.c
+ cc -o foo foo.o
+ % <userinput>scons -Q bar</userinput>
+ Don't forget to copy `bar' to the archive!
+ cc -o bar.o -c bar.c
+ cc -o bar bar.o
</screen>
- </section>
-
- <section>
- <title>Multiple Values From a List: the &ListOption; Build Option</title>
-
<para>
- Another way in which you might want to allow users
- to control build option is to
- specify a list of one or more legal values.
- &SCons; supports this through the &ListOption; function.
- If, for example, we want a user to be able to set a
- &COLORS; option to one or more of the legal list of values:
+ Another practical use for the &COMMAND_LINE_TARGETS; variable
+ might be to speed up a build
+ by only reading certain subsidiary &SConscript;
+ files if a specific target is requested.
</para>
- <programlisting>
- opts = Options('custom.py')
- opts.Add(ListOption('COLORS', 'List of colors', 0,
- ['red', 'green', 'blue']))
- env = Environment(options = opts,
- CPPDEFINES={'COLORS' : '"${COLORS}"'})
- env.Program('foo.c')
- </programlisting>
+ </section>
+
+ <section>
+ <title>Controlling the Default Targets: the &Default; Function</title>
<para>
- A user can now specify a comma-separated list
- of legal values,
- which will get translated into a space-separated
- list for passing to the any build commands:
+ One of the most basic things you can control
+ is which targets &SCons; will build by default--that is,
+ when there are no targets specified on the command line.
+ As mentioned previously,
+ &SCons; will normally build every target
+ in or below the current directory
+ by default--that is, when you don't
+ explicitly specify one or more targets
+ on the command line.
+ Sometimes, however, you may want
+ to specify explicitly that only
+ certain programs, or programs in certain directories,
+ should be built by default.
+ You do this with the &Default; function:
</para>
- <screen>
- % <userinput>scons -Q COLORS=red,blue foo.o</userinput>
- cc -o foo.o -c -DCOLORS="red blue" foo.c
- % <userinput>scons -Q COLORS=blue,green,red foo.o</userinput>
- cc -o foo.o -c -DCOLORS="blue green red" foo.c
- </screen>
+ <programlisting>
+ env = Environment()
+ hello = env.Program('hello.c')
+ env.Program('goodbye.c')
+ Default(hello)
+ </programlisting>
<para>
- In addition, the &ListOption; function
- allows the user to specify explicit keywords of
- &all; or &none;
- to select all of the legal values,
- or none of them, respectively:
+ This &SConstruct; file knows how to build two programs,
+ &hello; and &goodbye;,
+ but only builds the
+ &hello; program by default:
</para>
<screen>
- % <userinput>scons -Q COLORS=all foo.o</userinput>
- cc -o foo.o -c -DCOLORS="red green blue" foo.c
- % <userinput>scons -Q COLORS=none foo.o</userinput>
- cc -o foo.o -c -DCOLORS="" foo.c
+ % <userinput>scons -Q</userinput>
+ cc -o hello.o -c hello.c
+ cc -o hello hello.o
+ % <userinput>scons -Q</userinput>
+ scons: `hello' is up to date.
+ % <userinput>scons -Q goodbye</userinput>
+ cc -o goodbye.o -c goodbye.c
+ cc -o goodbye goodbye.o
</screen>
<para>
- And, of course, an illegal value
- still generates an error message:
+ Note that, even when you use the &Default;
+ function in your &SConstruct; file,
+ you can still explicitly specify the current directory
+ (<literal>.</literal>) on the command line
+ to tell &SCons; to build
+ everything in (or below) the current directory:
</para>
<screen>
- % <userinput>scons -Q COLORS=magenta foo.o</userinput>
-
- scons: *** Error converting option: COLORS
- Invalid value(s) for option: magenta
- File "/home/my/project/SConstruct", line 5, in <module>
+ % <userinput>scons -Q .</userinput>
+ cc -o goodbye.o -c goodbye.c
+ cc -o goodbye goodbye.o
+ cc -o hello.o -c hello.c
+ cc -o hello hello.o
</screen>
- </section>
-
- <section>
- <title>Path Names: the &PathOption; Build Option</title>
-
<para>
- &SCons; supports a &PathOption; function
- to make it easy to create a build option
- to control an expected path name.
- If, for example, you need to
- define a variable in the preprocessor
- that controls the location of a
- configuration file:
+ You can also call the &Default;
+ function more than once,
+ in which case each call
+ adds to the list of targets to be built by default:
</para>
<programlisting>
- opts = Options('custom.py')
- opts.Add(PathOption('CONFIG',
- 'Path to configuration file',
- '/etc/my_config'))
- env = Environment(options = opts,
- CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'})
- env.Program('foo.c')
+ env = Environment()
+ prog1 = env.Program('prog1.c')
+ Default(prog1)
+ prog2 = env.Program('prog2.c')
+ prog3 = env.Program('prog3.c')
+ Default(prog3)
</programlisting>
<para>
- This then allows the user to
- override the &CONFIG; build option
- on the command line as necessary:
+ Or you can specify more than one target
+ in a single call to the &Default; function:
</para>
- <screen>
- % <userinput>scons -Q foo.o</userinput>
- cc -o foo.o -c -DCONFIG_FILE="/etc/my_config" foo.c
- % <userinput>scons -Q CONFIG=/usr/local/etc/other_config foo.o</userinput>
- scons: `foo.o' is up to date.
- </screen>
+ <programlisting>
+ env = Environment()
+ prog1 = env.Program('prog1.c')
+ prog2 = env.Program('prog2.c')
+ prog3 = env.Program('prog3.c')
+ Default(prog1, prog3)
+ </programlisting>
<para>
- By default, &PathOption; checks to make sure
- that the specified path exists and generates an error if it
- doesn't:
+ Either of these last two examples
+ will build only the
+ <application>prog1</application>
+ and
+ <application>prog3</application>
+ programs by default:
</para>
<screen>
- % <userinput>scons -Q CONFIG=/does/not/exist foo.o</userinput>
-
- scons: *** Path for option CONFIG does not exist: /does/not/exist
- File "/home/my/project/SConstruct", line 6, in <module>
+ % <userinput>scons -Q</userinput>
+ cc -o prog1.o -c prog1.c
+ cc -o prog1 prog1.o
+ cc -o prog3.o -c prog3.c
+ cc -o prog3 prog3.o
+ % <userinput>scons -Q .</userinput>
+ cc -o prog2.o -c prog2.c
+ cc -o prog2 prog2.o
</screen>
<para>
- &PathOption; provides a number of methods
- that you can use to change this behavior.
- If you want to ensure that any specified paths are,
- in fact, files and not directories,
- use the &PathOption_PathIsFile; method:
+ You can list a directory as
+ an argument to &Default;:
</para>
<programlisting>
- opts = Options('custom.py')
- opts.Add(PathOption('CONFIG',
- 'Path to configuration file',
- '/etc/my_config',
- PathOption.PathIsFile))
- env = Environment(options = opts,
- CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'})
- env.Program('foo.c')
+ env = Environment()
+ env.Program(['prog1/main.c', 'prog1/foo.c'])
+ env.Program(['prog2/main.c', 'prog2/bar.c'])
+ Default('prog1')
</programlisting>
<para>
- Conversely, to ensure that any specified paths are
- directories and not files,
- use the &PathOption_PathIsDir; method:
+ In which case only the target(s) in that
+ directory will be built by default:
</para>
- <programlisting>
- opts = Options('custom.py')
- opts.Add(PathOption('DBDIR',
- 'Path to database directory',
- '/var/my_dbdir',
- PathOption.PathIsDir))
- env = Environment(options = opts,
- CPPDEFINES={'DBDIR' : '"$DBDIR"'})
- env.Program('foo.c')
- </programlisting>
+ <screen>
+ % <userinput>scons -Q</userinput>
+ cc -o prog1/foo.o -c prog1/foo.c
+ cc -o prog1/main.o -c prog1/main.c
+ cc -o prog1/main prog1/main.o prog1/foo.o
+ % <userinput>scons -Q</userinput>
+ scons: `prog1' is up to date.
+ % <userinput>scons -Q .</userinput>
+ cc -o prog2/bar.o -c prog2/bar.c
+ cc -o prog2/main.o -c prog2/main.c
+ cc -o prog2/main prog2/main.o prog2/bar.o
+ </screen>
<para>
- If you want to make sure that any specified paths
- are directories,
- and you would like the directory created
- if it doesn't already exist,
- use the &PathOption_PathIsDirCreate; method:
+ Lastly, if for some reason you don't want
+ any targets built by default,
+ you can use the Python <literal>None</literal>
+ variable:
</para>
<programlisting>
- opts = Options('custom.py')
- opts.Add(PathOption('DBDIR',
- 'Path to database directory',
- '/var/my_dbdir',
- PathOption.PathIsDirCreate))
- env = Environment(options = opts,
- CPPDEFINES={'DBDIR' : '"$DBDIR"'})
- env.Program('foo.c')
+ env = Environment()
+ prog1 = env.Program('prog1.c')
+ prog2 = env.Program('prog2.c')
+ Default(None)
</programlisting>
<para>
- Lastly, if you don't care whether the path exists,
- is a file, or a directory,
- use the &PathOption_PathAccept; method
- to accept any path that the user supplies:
+ Which would produce build output like:
</para>
- <programlisting>
- opts = Options('custom.py')
- opts.Add(PathOption('OUTPUT',
- 'Path to output file or directory',
- None,
- PathOption.PathAccept))
- env = Environment(options = opts,
- CPPDEFINES={'OUTPUT' : '"$OUTPUT"'})
- env.Program('foo.c')
- </programlisting>
+ <screen>
+ % <userinput>scons -Q</userinput>
+ scons: *** No targets specified and no Default() targets found. Stop.
+ % <userinput>scons -Q .</userinput>
+ cc -o prog1.o -c prog1.c
+ cc -o prog1 prog1.o
+ cc -o prog2.o -c prog2.c
+ cc -o prog2 prog2.o
+ </screen>
+
+ <section>
+ <title>Fetching the List of Default Targets: the &DEFAULT_TARGETS; Variable</title>
+
+ <para>
+
+ &SCons; supports a &DEFAULT_TARGETS; variable
+ that lets you get at the current list of default targets.
+ The &DEFAULT_TARGETS variable has
+ two important differences from the &COMMAND_LINE_TARGETS; variable.
+ First, the &DEFAULT_TARGETS; variable is a list of
+ internal &SCons; nodes,
+ so you need to convert the list elements to strings
+ if you want to print them or look for a specific target name.
+ Fortunately, you can do this easily
+ by using the Python <function>map</function> function
+ to run the list through <function>str</function>:
+
+ </para>
+
+ <programlisting>
+ prog1 = Program('prog1.c')
+ Default(prog1)
+ print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS)
+ </programlisting>
+
+ <para>
+
+ (Keep in mind that all of the manipulation of the
+ &DEFAULT_TARGETS; list takes place during the
+ first phase when &SCons; is reading up the &SConscript; files,
+ which is obvious if
+ we leave off the <literal>-Q</literal> flag when we run &SCons;:)
+
+ </para>
+
+ <screen>
+ % <userinput>scons</userinput>
+ scons: Reading SConscript files ...
+ DEFAULT_TARGETS is ['prog1']
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ cc -o prog1.o -c prog1.c
+ cc -o prog1 prog1.o
+ scons: done building targets.
+ </screen>
+
+ <para>
+
+ Second,
+ the contents of the &DEFAULT_TARGETS; list change
+ in response to calls to the &Default;: function,
+ as you can see from the following &SConstruct; file:
+
+ </para>
+
+ <programlisting>
+ prog1 = Program('prog1.c')
+ Default(prog1)
+ print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS)
+ prog2 = Program('prog2.c')
+ Default(prog2)
+ print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS)
+ </programlisting>
+
+ <para>
+
+ Which yields the output:
+
+ </para>
+
+ <screen>
+ % <userinput>scons</userinput>
+ scons: Reading SConscript files ...
+ DEFAULT_TARGETS is now ['prog1']
+ DEFAULT_TARGETS is now ['prog1', 'prog2']
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ cc -o prog1.o -c prog1.c
+ cc -o prog1 prog1.o
+ cc -o prog2.o -c prog2.c
+ cc -o prog2 prog2.o
+ scons: done building targets.
+ </screen>
+
+ <para>
+
+ In practice, this simply means that you
+ need to pay attention to the order in
+ which you call the &Default; function
+ and refer to the &DEFAULT_TARGETS; list,
+ to make sure that you don't examine the
+ list before you've added the default targets
+ you expect to find in it.
+
+ </para>
+
+ </section>
</section>
<section>
- <title>Enabled/Disabled Path Names: the &PackageOption; Build Option</title>
+ <title>Fetching the List of Build Targets, Regardless of Origin: the &BUILD_TARGETS; Variable</title>
<para>
- Sometimes you want to give users
- even more control over a path name variable,
- allowing them to explicitly enable or
- disable the path name
- by using <literal>yes</literal> or <literal>no</literal> keywords,
- in addition to allow them
- to supply an explicit path name.
- &SCons; supports the &PackageOption;
- function to support this:
+ We've already been introduced to the
+ &COMMAND_LINE_TARGETS; variable,
+ which contains a list of targets specified on the command line,
+ and the &DEFAULT_TARGETS; variable,
+ which contains a list of targets specified
+ via calls to the &Default; method or function.
+ Sometimes, however,
+ you want a list of whatever targets
+ &SCons; will try to build,
+ regardless of whether the targets came from the
+ command line or a &Default; call.
+ You could code this up by hand, as follows:
</para>
<programlisting>
- opts = Options('custom.py')
- opts.Add(PackageOption('PACKAGE',
- 'Location package',
- '/opt/location'))
- env = Environment(options = opts,
- CPPDEFINES={'PACKAGE' : '"$PACKAGE"'})
- env.Program('foo.c')
+ if COMMAND_LINE_TARGETS:
+ targets = COMMAND_LINE_TARGETS
+ else:
+ targets = DEFAULT_TARGETS
</programlisting>
<para>
- When the &SConscript; file uses the &PackageOption; funciton,
- user can now still use the default
- or supply an overriding path name,
- but can now explicitly set the
- specified variable to a value
- that indicates the package should be enabled
- (in which case the default should be used)
- or disabled:
+ &SCons;, however, provides a convenient
+ &BUILD_TARGETS; variable
+ that eliminates the need for this by-hand manipulation.
+ Essentially, the &BUILD_TARGETS; variable
+ contains a list of the command-line targets,
+ if any were specified,
+ and if no command-line targets were specified,
+ it contains a list of the targets specified
+ via the &Default; method or function.
</para>
- <screen>
- % <userinput>scons -Q foo.o</userinput>
- cc -o foo.o -c -DPACKAGE="/opt/location" foo.c
- % <userinput>scons -Q PACKAGE=/usr/local/location foo.o</userinput>
- cc -o foo.o -c -DPACKAGE="/usr/local/location" foo.c
- % <userinput>scons -Q PACKAGE=yes foo.o</userinput>
- cc -o foo.o -c -DPACKAGE="True" foo.c
- % <userinput>scons -Q PACKAGE=no foo.o</userinput>
- cc -o foo.o -c -DPACKAGE="False" foo.c
- </screen>
+ <para>
- </section>
+ Because &BUILD_TARGETS; may contain a list of &SCons; nodes,
+ you must convert the list elements to strings
+ if you want to print them or look for a specific target name,
+ just like the &DEFAULT_TARGETS; list:
- </section>
+ </para>
- <section>
- <title>Adding Multiple Command-Line Build Options at Once</title>
+ <programlisting>
+ prog1 = Program('prog1.c')
+ Program('prog2.c')
+ Default(prog1)
+ print "BUILD_TARGETS is", map(str, BUILD_TARGETS)
+ </programlisting>
- <para>
+ <para>
- Lastly, &SCons; provides a way to add
- multiple build options to an &Options; object at once.
- Instead of having to call the &Add; method
- multiple times,
- you can call the &AddOptions;
- method with a list of build options
- to be added to the object.
- Each build option is specified
- as either a tuple of arguments,
- just like you'd pass to the &Add; method itself,
- or as a call to one of the canned
- functions for pre-packaged command-line build options.
- in any order:
+ Notice how the value of &BUILD_TARGETS;
+ changes depending on whether a target is
+ specified on the command line:
- </para>
+ </para>
- <programlisting>
- opts = Options()
- opts.AddOptions(
- ('RELEASE', 'Set to 1 to build for release', 0),
- ('CONFIG', 'Configuration file', '/etc/my_config'),
- BoolOption('warnings', 'compilation with -Wall and similiar', 1),
- EnumOption('debug', 'debug output and symbols', 'no',
- allowed_values=('yes', 'no', 'full'),
- map={}, ignorecase=0), # case sensitive
- ListOption('shared',
- 'libraries to build as shared libraries',
- 'all',
- names = list_of_libs),
- PackageOption('x11',
- 'use X11 installed here (yes = search some places)',
- 'yes'),
- PathOption('qtdir', 'where the root of Qt is installed', qtdir),
- )
- </programlisting>
+ <screen>
+ % <userinput>scons -Q</userinput>
+ BUILD_TARGETS is ['prog1']
+ cc -o prog1.o -c prog1.c
+ cc -o prog1 prog1.o
+ % <userinput>scons -Q prog2</userinput>
+ BUILD_TARGETS is ['prog2']
+ cc -o prog2.o -c prog2.c
+ cc -o prog2 prog2.o
+ % <userinput>scons -Q -c .</userinput>
+ BUILD_TARGETS is ['.']
+ Removed prog1.o
+ Removed prog1
+ Removed prog2.o
+ Removed prog2
+ </screen>
- <para>
- </para>
+ </section>
</section>
-
- <!--
-
- AddOption() function for things like - -prefix=, - -force
-
- -->
</para>
+ <!--
+
+ We want to generate the output as follows,
+ but our "surrogate" system for generating the
+ output seems to get this wrong.
+ Just in-line the output for now.
+
<scons_output example="MD5-timestamp" os="posix">
<scons_output_command>scons -Q hello</scons_output_command>
<scons_output_command>touch hello.c</scons_output_command>
<scons_output_command>scons -Q hello</scons_output_command>
</scons_output>
+ -->
+
+ <screen>
+ % <userinput>scons -Q hello</userinput>
+ cc -o hello.o -c hello.c
+ cc -o hello hello.o
+ % <userinput>touch hello.c</userinput>
+ % <userinput>scons -Q hello</userinput>
+ scons: `hello' is up to date.
+ % <userinput>edit hello.c</userinput>
+ [CHANGE THE CONTENTS OF hello.c]
+ % <userinput>scons -Q hello</userinput>
+ cc -o hello.o -c hello.c
+ cc -o hello hello.o
+ </screen>
+
<para>
However, the second call to &SCons; in the above output,
<para>
Note that in the function definition,
- the <literal>dependency</literal>
+ the <varname>dependency</varname>
(input file) is the first argument,
- and then the <literal>target</literal>.
+ and then the ⌖.
Both of these are passed to the functions as
SCons &Node; objects,
which we convert to strings using the Python
<function>str()</function>.
- The third argument, <literal>prev_ni</literal>,
+
+ </para>
+
+ <para>
+
+ The third argument, <varname>prev_ni</varname>,
is an object that holds the
signature or timestamp information
that was recorded about the dependency
the last time the target was built.
+ A <varname>prev_ni</varname> object can hold
+ different information,
+ depending on the type of thing that the
+ <varname>dependency</varname> argument represents.
+ For normal files,
+ the <varname>prev_ni</varname> object
+ has the following attributes:
</para>
+ <variablelist>
+
+ <varlistentry>
+ <term>.csig</term>
+
+ <listitem>
+ <para>
+ The <emphasis>content signature</emphasis>,
+ or MD5 checksum, of the contents of the
+ <varname>dependency</varname>
+ file the list time the ⌖ was built.
+ </para>
+ </listitem>
+
+ </varlistentry>
+
+ <varlistentry>
+ <term>.size</term>
+
+ <listitem>
+ <para>
+ The size in bytes of the <varname>dependency</varname>
+ file the list time the target was built.
+ </para>
+ </listitem>
+
+ </varlistentry>
+
+ <varlistentry>
+ <term>.timestamp</term>
+
+ <listitem>
+ <para>
+ The modification time of the <varname>dependency</varname>
+ file the list time the ⌖ was built.
+ </para>
+ </listitem>
+
+ </varlistentry>
+
+ </variablelist>
+
<para>
Note that ignoring some of the arguments
cc -o hello hello.o
</screen>
+ <para>
+
+ Note that the dependency
+ (the second argument to &Depends;)
+ may also be a list of Node objects
+ (for example, as returned by a call to a Builder):
+
+ </para>
+
+ <programlisting>
+ hello = Program('hello.c')
+ goodbye = Program('goodbye.c')
+ Depends(hello, goodbye)
+ </programlisting>
+
+ <para>
+
+ in which case the dependency or dependencies
+ will be built before the target(s):
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q hello</userinput>
+ cc -c goodbye.c -o goodbye.o
+ cc -o goodbye goodbye.o
+ cc -c hello.c -o hello.o
+ cc -o hello hello.o
+ </screen>
+
</section>
<section>
</file>
</scons_example>
- <!-- XXX mention that you can use arrays for target and source? -->
+ <!-- XXX mention that you can use lists for target and source? -->
<!--
<scons_output example="ignore">
</para>
<programlisting>
- hello = Program('hello.c')
+ hello = Program('hello.c', CPPPATH=['/usr/include'])
Ignore(hello, '/usr/include/stdio.h')
</programlisting>
</section>
+ <section>
+ <title>Order-Only Dependencies: the &Requires; Function</title>
+
+ <para>
+
+ Occasionally,
+ it may be useful to specify that a certain
+ file or directory must, if necessary,
+ be built or created before some other target is built,
+ but that changes to that file or directory
+ do <emphasis>not</emphasis>
+ require that the target itself be rebuilt.
+ Such a relationship is called an
+ <emphasis>order-only dependency</emphasis>
+ because it only affects the order in which
+ things must be built--the dependency before the target--but
+ it is not a strict dependency relationship
+ because the target should not
+ change in response to changes in the dependent file.
+
+ </para>
+
+ <para>
+
+ For example, suppose that you want to create a file
+ every time you run a build
+ that identifies the time the build was performed,
+ the version number, etc.,
+ and which is included in every program that you build.
+ The version file's contents will change every build.
+ If you specify a normal dependency relationship,
+ then every program that depends on
+ that file would be rebuilt every time you ran &SCons;.
+ For example, we could use some Python code in
+ a &SConstruct; file to create a new <filename>version.c</filename> file
+ with a string containing the current date every time
+ we run &SCons;,
+ and then link a program with the resulting object file
+ by listing <filename>version.c</filename> in the sources:
+
+ </para>
+
+ <scons_example name="no-Requires">
+ <file name="SConstruct" printme="1">
+ import time
+
+ version_c_text = """
+ char *date = "%s";
+ """ % time.ctime(time.time())
+ open('version.c', 'w').write(version_c_text)
+
+ hello = Program(['hello.c', 'version.c'])
+ </file>
+ <file name="hello.c">
+ extern char *date;
+ int main() { printf("Hello, %s! I was built: %s\n", date); }
+ </file>
+ </scons_example>
+
+ <para>
+
+ If we list <filename>version.c</filename> as an actual source file,
+ though, then <filename>version.o</filename>
+ will get rebuilt every time we run &SCons;
+ (because the &SConstruct; file itself changes
+ the contents of <filename>version.c</filename>)
+ and the <filename>hello</filename> executable
+ will get re-linked every time
+ (because the <filename>version.o</filename> file changes):
+
+ </para>
+
+ <!--
+
+ <scons_output example="no-Requires">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ gcc -o hello.o -c hello.c
+ gcc -o version.o -c version.c
+ gcc -o hello hello.o version.o
+ % <userinput>scons -Q</userinput>
+ gcc -o version.o -c version.c
+ gcc -o hello hello.o version.o
+ % <userinput>scons -Q</userinput>
+ gcc -o version.o -c version.c
+ gcc -o hello hello.o version.o
+ </screen>
+
+ <para>
+
+ One solution is to use the &Requires; function
+ to specify that the <filename>version.o</filename>
+ must be rebuilt before it is used by the link step,
+ but that changes to <filename>version.o</filename>
+ should not actually cause the <filename>hello</filename>
+ executable to be re-linked:
+
+ </para>
+
+ <scons_example name="Requires">
+ <file name="SConstruct" printme="1">
+ import time
+
+ version_c_text = """
+ char *date = "%s";
+ """ % time.ctime(time.time())
+ open('version.c', 'w').write(version_c_text)
+
+ version_obj = Object('version.c')
+
+ hello = Program('hello.c',
+ LINKFLAGS = str(version_obj[0]))
+
+ Requires(hello, version_obj)
+ </file>
+ <file name="hello.c">
+ extern char *date;
+ int main() { printf("Hello, %s! I was built: %s\n", date); }
+ </file>
+ </scons_example>
+
+ <para>
+
+ Notice that because we can no longer list <filename>version.c</filename>
+ as one of the sources for the <filename>hello</filename> program,
+ we have to find some other way to get it into the link command line.
+ For this example, we're cheating a bit and stuffing the
+ object file name (extracted from <literal>version_obj</literal>
+ list returned by the &b-Object; call)
+ into the &cv-link-LINKFLAGS; variable,
+ because &cv-LINKFLAGS; is already included
+ in the &cv-link-LINKCOM; command line.
+
+ </para>
+
+ <para>
+
+ With these changes,
+ we get the desired behavior of
+ re-building the <filename>version.o</filename> file,
+ and therefore re-linking the <filename>hello</filename> executable,
+ only when the <filename>hello.c</filename> has changed:
+
+ </para>
+
+ <scons_output example="Requires">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command output=" [CHANGE THE CONTENTS OF hello.c]">edit hello.c</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ </section>
+
<section>
<title>The &AlwaysBuild; Function</title>
</para>
+ <!--
+
+ We want to generate the output as follows,
+ but our "surrogate" system for generating the
+ output seems to get this wrong.
+ Just in-line the output for now.
+
+ <scons_output example="MD5-timestamp" os="posix">
+ <scons_output_command>scons -Q hello</scons_output_command>
+ <scons_output_command>touch hello.c</scons_output_command>
+ <scons_output_command>scons -Q hello</scons_output_command>
+ <scons_output_command output=" [CHANGE THE CONTENTS OF hello.c]">edit hello.c</scons_output_command>
+ <scons_output_command>scons -Q hello</scons_output_command>
+ </scons_output>
+
+ -->
+
<screen>
% <userinput>scons -Q hello</userinput>
cc -o hello.o -c hello.c
% <userinput>edit hello.c</userinput>
[CHANGE THE CONTENTS OF hello.c]
% <userinput>scons -Q hello</userinput>
- scons: `hello' is up to date.
+ cc -o hello.o -c hello.c
+ cc -o hello hello.o
</screen>
<para>
<para>
Note that in the function definition,
- the <literal>dependency</literal>
+ the <varname>dependency</varname>
(input file) is the first argument,
- and then the <literal>target</literal>.
+ and then the ⌖.
Both of these are passed to the functions as
SCons &Node; objects,
which we convert to strings using the Python
<function>str()</function>.
- The third argument, <literal>prev_ni</literal>,
+
+ </para>
+
+ <para>
+
+ The third argument, <varname>prev_ni</varname>,
is an object that holds the
signature or timestamp information
that was recorded about the dependency
the last time the target was built.
+ A <varname>prev_ni</varname> object can hold
+ different information,
+ depending on the type of thing that the
+ <varname>dependency</varname> argument represents.
+ For normal files,
+ the <varname>prev_ni</varname> object
+ has the following attributes:
</para>
+ <variablelist>
+
+ <varlistentry>
+ <term>.csig</term>
+
+ <listitem>
+ <para>
+ The <emphasis>content signature</emphasis>,
+ or MD5 checksum, of the contents of the
+ <varname>dependency</varname>
+ file the list time the ⌖ was built.
+ </para>
+ </listitem>
+
+ </varlistentry>
+
+ <varlistentry>
+ <term>.size</term>
+
+ <listitem>
+ <para>
+ The size in bytes of the <varname>dependency</varname>
+ file the list time the target was built.
+ </para>
+ </listitem>
+
+ </varlistentry>
+
+ <varlistentry>
+ <term>.timestamp</term>
+
+ <listitem>
+ <para>
+ The modification time of the <varname>dependency</varname>
+ file the list time the ⌖ was built.
+ </para>
+ </listitem>
+
+ </varlistentry>
+
+ </variablelist>
+
<para>
Note that ignoring some of the arguments
cc -o hello hello.o
</screen>
+ <para>
+
+ Note that the dependency
+ (the second argument to &Depends;)
+ may also be a list of Node objects
+ (for example, as returned by a call to a Builder):
+
+ </para>
+
+ <programlisting>
+ hello = Program('hello.c')
+ goodbye = Program('goodbye.c')
+ Depends(hello, goodbye)
+ </programlisting>
+
+ <para>
+
+ in which case the dependency or dependencies
+ will be built before the target(s):
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q hello</userinput>
+ cc -c goodbye.c -o goodbye.o
+ cc -o goodbye goodbye.o
+ cc -c hello.c -o hello.o
+ cc -o hello hello.o
+ </screen>
+
</section>
<section>
Ignore(hello, 'hello.h')
</programlisting>
- <!-- XXX mention that you can use arrays for target and source? -->
+ <!-- XXX mention that you can use lists for target and source? -->
<!--
<scons_output example="ignore">
</para>
<programlisting>
- hello = Program('hello.c')
+ hello = Program('hello.c', CPPPATH=['/usr/include'])
Ignore(hello, '/usr/include/stdio.h')
</programlisting>
</section>
+ <section>
+ <title>Order-Only Dependencies: the &Requires; Function</title>
+
+ <para>
+
+ Occasionally,
+ it may be useful to specify that a certain
+ file or directory must, if necessary,
+ be built or created before some other target is built,
+ but that changes to that file or directory
+ do <emphasis>not</emphasis>
+ require that the target itself be rebuilt.
+ Such a relationship is called an
+ <emphasis>order-only dependency</emphasis>
+ because it only affects the order in which
+ things must be built--the dependency before the target--but
+ it is not a strict dependency relationship
+ because the target should not
+ change in response to changes in the dependent file.
+
+ </para>
+
+ <para>
+
+ For example, suppose that you want to create a file
+ every time you run a build
+ that identifies the time the build was performed,
+ the version number, etc.,
+ and which is included in every program that you build.
+ The version file's contents will change every build.
+ If you specify a normal dependency relationship,
+ then every program that depends on
+ that file would be rebuilt every time you ran &SCons;.
+ For example, we could use some Python code in
+ a &SConstruct; file to create a new <filename>version.c</filename> file
+ with a string containing the current date every time
+ we run &SCons;,
+ and then link a program with the resulting object file
+ by listing <filename>version.c</filename> in the sources:
+
+ </para>
+
+ <programlisting>
+ import time
+
+ version_c_text = """
+ char *date = "%s";
+ """ % time.ctime(time.time())
+ open('version.c', 'w').write(version_c_text)
+
+ hello = Program(['hello.c', 'version.c'])
+ </programlisting>
+
+ <para>
+
+ If we list <filename>version.c</filename> as an actual source file,
+ though, then <filename>version.o</filename>
+ will get rebuilt every time we run &SCons;
+ (because the &SConstruct; file itself changes
+ the contents of <filename>version.c</filename>)
+ and the <filename>hello</filename> executable
+ will get re-linked every time
+ (because the <filename>version.o</filename> file changes):
+
+ </para>
+
+ <!--
+
+ <scons_output example="no-Requires">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ gcc -o hello.o -c hello.c
+ gcc -o version.o -c version.c
+ gcc -o hello hello.o version.o
+ % <userinput>scons -Q</userinput>
+ gcc -o version.o -c version.c
+ gcc -o hello hello.o version.o
+ % <userinput>scons -Q</userinput>
+ gcc -o version.o -c version.c
+ gcc -o hello hello.o version.o
+ </screen>
+
+ <para>
+
+ One solution is to use the &Requires; function
+ to specify that the <filename>version.o</filename>
+ must be rebuilt before it is used by the link step,
+ but that changes to <filename>version.o</filename>
+ should not actually cause the <filename>hello</filename>
+ executable to be re-linked:
+
+ </para>
+
+ <programlisting>
+ import time
+
+ version_c_text = """
+ char *date = "%s";
+ """ % time.ctime(time.time())
+ open('version.c', 'w').write(version_c_text)
+
+ version_obj = Object('version.c')
+
+ hello = Program('hello.c',
+ LINKFLAGS = str(version_obj[0]))
+
+ Requires(hello, version_obj)
+ </programlisting>
+
+ <para>
+
+ Notice that because we can no longer list <filename>version.c</filename>
+ as one of the sources for the <filename>hello</filename> program,
+ we have to find some other way to get it into the link command line.
+ For this example, we're cheating a bit and stuffing the
+ object file name (extracted from <literal>version_obj</literal>
+ list returned by the &b-Object; call)
+ into the &cv-link-LINKFLAGS; variable,
+ because &cv-LINKFLAGS; is already included
+ in the &cv-link-LINKCOM; command line.
+
+ </para>
+
+ <para>
+
+ With these changes,
+ we get the desired behavior of
+ re-building the <filename>version.o</filename> file,
+ and therefore re-linking the <filename>hello</filename> executable,
+ only when the <filename>hello.c</filename> has changed:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ cc -o hello.o -c hello.c
+ cc -o version.o -c version.c
+ cc -o hello version.o hello.o
+ % <userinput>scons -Q</userinput>
+ scons: `.' is up to date.
+ % <userinput>edit hello.c</userinput>
+ [CHANGE THE CONTENTS OF hello.c]
+ % <userinput>scons -Q</userinput>
+ cc -o hello.o -c hello.c
+ cc -o hello version.o hello.o
+ % <userinput>scons -Q</userinput>
+ scons: `.' is up to date.
+ </screen>
+
+ </section>
+
<section>
<title>The &AlwaysBuild; Function</title>
<!--
- __COPYRIGHT__
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
- KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ __COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-->
Construction variables from a construction environment are expanded
by preceding the keyword with a C<%> (percent sign):
- Construction variables:
+ Construction variables:
XYZZY => 'abracadabra',
- The string: "The magic word is: %XYZZY!"
- expands to: "The magic word is: abracadabra!"
+ The string: "The magic word is: %XYZZY!"
+ expands to: "The magic word is: abracadabra!"
A construction variable name may be surrounded by C<{> and C<}> (curly
braces), which are stripped as part of the expansion. This can
sometimes be necessary to separate a variable expansion from trailing
alphanumeric characters:
- Construction variables:
+ Construction variables:
OPT => 'value1',
OPTION => 'value2',
- The string: "%OPT %{OPT}ION %OPTION %{OPTION}"
- expands to: "value1 value1ION value2 value2"
+ The string: "%OPT %{OPT}ION %OPTION %{OPTION}"
+ expands to: "value1 value1ION value2 value2"
Construction variable expansion is recursive, that is, a string
containing C<%->expansions after substitution will be re-expanded until
no further substitutions can be made:
- Construction variables:
+ Construction variables:
STRING => 'The result is: %FOO',
FOO => '%BAR',
BAR => 'final value',
- The string: "The string says: %STRING"
- expands to: "The string says: The result is: final value"
+ The string: "The string says: %STRING"
+ expands to: "The string says: The result is: final value"
If a construction variable is not defined in an environment, then the
null string is substituted:
- Construction variables:
+ Construction variables:
FOO => 'value1',
BAR => 'value2',
- The string: "%FOO <%NO_VARIABLE> %BAR"
- expands to: "value1 <> value2"
+ The string: "%FOO <%NO_VARIABLE> %BAR"
+ expands to: "value1 <> value2"
A doubled C<%%> will be replaced by a single C<%>:
- The string: "Here is a percent sign: %%"
- expands to: "Here is a percent sign: %"
+ The string: "Here is a percent sign: %%"
+ expands to: "Here is a percent sign: %"
=head2 Default construction variables
When you specify no arguments when creating a new construction
environment:
- $env = new cons();
+ $env = new cons();
Cons creates a reference to a new, default construction
environment. This contains a number of construction variables and some
methods. At the present writing, the default construction variables on a
UNIX system are:
- CC => 'cc',
- CFLAGS => '',
- CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>',
- CXX => '%CC',
- CXXFLAGS => '%CFLAGS',
- CXXCOM => '%CXX %CXXFLAGS %_IFLAGS -c %< -o %>',
- INCDIRPREFIX => '-I',
- INCDIRSUFFIX => '',
- LINK => '%CXX',
- LINKCOM => '%LINK %LDFLAGS -o %> %< %_LDIRS %LIBS',
- LINKMODULECOM => '%LD -r -o %> %<',
- LIBDIRPREFIX => '-L',
- LIBDIRSUFFIX => '',
- AR => 'ar',
- ARFLAGS => 'r',
- ARCOM => ['%AR %ARFLAGS %> %<', '%RANLIB %>'],
- RANLIB => 'ranlib',
- AS => 'as',
- ASFLAGS => '',
- ASCOM => '%AS %ASFLAGS %< -o %>',
- LD => 'ld',
- LDFLAGS => '',
- PREFLIB => 'lib',
- SUFLIB => '.a',
- SUFLIBS => '.so:.a',
- SUFOBJ => '.o',
- SIGNATURE => [ '*' => 'build' ],
- ENV => { 'PATH' => '/bin:/usr/bin' },
+ CC => 'cc',
+ CFLAGS => '',
+ CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>',
+ CXX => '%CC',
+ CXXFLAGS => '%CFLAGS',
+ CXXCOM => '%CXX %CXXFLAGS %_IFLAGS -c %< -o %>',
+ INCDIRPREFIX => '-I',
+ INCDIRSUFFIX => '',
+ LINK => '%CXX',
+ LINKCOM => '%LINK %LDFLAGS -o %> %< %_LDIRS %LIBS',
+ LINKMODULECOM => '%LD -r -o %> %<',
+ LIBDIRPREFIX => '-L',
+ LIBDIRSUFFIX => '',
+ AR => 'ar',
+ ARFLAGS => 'r',
+ ARCOM => ['%AR %ARFLAGS %> %<', '%RANLIB %>'],
+ RANLIB => 'ranlib',
+ AS => 'as',
+ ASFLAGS => '',
+ ASCOM => '%AS %ASFLAGS %< -o %>',
+ LD => 'ld',
+ LDFLAGS => '',
+ PREFLIB => 'lib',
+ SUFLIB => '.a',
+ SUFLIBS => '.so:.a',
+ SUFOBJ => '.o',
+ SIGNATURE => [ '*' => 'build' ],
+ ENV => { 'PATH' => '/bin:/usr/bin' },
And on a Windows system (Windows NT), the default construction variables
are (unless the default rule style is set using the B<DefaultRules>
method):
- CC => 'cl',
- CFLAGS => '/nologo',
- CCCOM => '%CC %CFLAGS %_IFLAGS /c %< /Fo%>',
- CXXCOM => '%CXX %CXXFLAGS %_IFLAGS /c %< /Fo%>',
- INCDIRPREFIX => '/I',
- INCDIRSUFFIX => '',
- LINK => 'link',
- LINKCOM => '%LINK %LDFLAGS /out:%> %< %_LDIRS %LIBS',
- LINKMODULECOM => '%LD /r /o %> %<',
- LIBDIRPREFIX => '/LIBPATH:',
- LIBDIRSUFFIX => '',
- AR => 'lib',
- ARFLAGS => '/nologo ',
- ARCOM => "%AR %ARFLAGS /out:%> %<",
- RANLIB => '',
- LD => 'link',
- LDFLAGS => '/nologo ',
- PREFLIB => '',
- SUFEXE => '.exe',
- SUFLIB => '.lib',
- SUFLIBS => '.dll:.lib',
- SUFOBJ => '.obj',
- SIGNATURE => [ '*' => 'build' ],
+ CC => 'cl',
+ CFLAGS => '/nologo',
+ CCCOM => '%CC %CFLAGS %_IFLAGS /c %< /Fo%>',
+ CXXCOM => '%CXX %CXXFLAGS %_IFLAGS /c %< /Fo%>',
+ INCDIRPREFIX => '/I',
+ INCDIRSUFFIX => '',
+ LINK => 'link',
+ LINKCOM => '%LINK %LDFLAGS /out:%> %< %_LDIRS %LIBS',
+ LINKMODULECOM => '%LD /r /o %> %<',
+ LIBDIRPREFIX => '/LIBPATH:',
+ LIBDIRSUFFIX => '',
+ AR => 'lib',
+ ARFLAGS => '/nologo ',
+ ARCOM => "%AR %ARFLAGS /out:%> %<",
+ RANLIB => '',
+ LD => 'link',
+ LDFLAGS => '/nologo ',
+ PREFLIB => '',
+ SUFEXE => '.exe',
+ SUFLIB => '.lib',
+ SUFLIBS => '.dll:.lib',
+ SUFOBJ => '.obj',
+ SIGNATURE => [ '*' => 'build' ],
These variables are used by the various methods associated with the
environment. In particular, any method that ultimately invokes an external
files and arranges to derive, if necessary, the corresponding object
files:
- Objects $env 'foo.c', 'bar.c';
+ Objects $env 'foo.c', 'bar.c';
This will arrange to produce, if necessary, F<foo.o> and F<bar.o>. The
command invoked is simply C<%CCCOM>, which expands, through substitution,
those will be deleted from the list provided by C<%E<lt>>. Consider the
following command found in a F<Conscript> file in the F<test> directory:
- Command $env 'tgt', qw(foo bar baz), qq(
+ Command $env 'tgt', qw(foo bar baz), qq(
echo %< -i %1 > %>
echo %< -i %2 >> %>
echo %< -i %3 >> %>
- );
+ );
If F<tgt> needed to be updated, then this would result in the execution of
the following commands, assuming that no remapping has been established for
the F<test> directory:
- echo test/bar test/baz -i test/foo > test/tgt
- echo test/foo test/baz -i test/bar >> test/tgt
- echo test/foo test/bar -i test/baz >> test/tgt
+ echo test/bar test/baz -i test/foo > test/tgt
+ echo test/foo test/baz -i test/bar >> test/tgt
+ echo test/foo test/bar -i test/baz >> test/tgt
=back
Any of the above pseudo-variables may be followed immediately by one of
the following suffixes to select a portion of the expanded path name:
- :a the absolute path to the file name
- :b the directory plus the file name stripped of any suffix
- :d the directory
- :f the file name
- :s the file name suffix
- :F the file name stripped of any suffix
- :S the absolute path path to a Linked source file
+ :a the absolute path to the file name
+ :b the directory plus the file name stripped of any suffix
+ :d the directory
+ :f the file name
+ :s the file name suffix
+ :F the file name stripped of any suffix
+ :S the absolute path path to a Linked source file
Continuing with the above example, C<%E<lt>:f> would expand to C<foo bar baz>,
and C<%E<gt>:d> would expand to C<test>.
replace the contents of the brackets in the command line. For example,
given an existing input file named F<tgt.in>:
- @keywords = qw(foo bar baz);
- $env = new cons(X_COMMA => sub { join(",", @_) });
- Command $env 'tgt', 'tgt.in', qq(
+ @keywords = qw(foo bar baz);
+ $env = new cons(X_COMMA => sub { join(",", @_) });
+ Command $env 'tgt', 'tgt.in', qq(
echo '# Keywords: %[X_COMMA @keywords %]' > %>
cat %< >> %>
- );
+ );
This will execute:
- echo '# Keywords: foo,bar,baz' > tgt
- cat tgt.in >> tgt
+ echo '# Keywords: foo,bar,baz' > tgt
+ cat tgt.in >> tgt
=item %( %)
passed to the various construction methods according to the expansion
rules described above:
- $env = new cons(
+ $env = new cons(
DESTDIR => 'programs',
SRCDIR => 'src',
- );
- Program $env '%DESTDIR/hello', '%SRCDIR/hello.c';
+ );
+ Program $env '%DESTDIR/hello', '%SRCDIR/hello.c';
This allows for flexible configuration, through the construction
environment, of directory names, suffixes, etc.
-=head1 Default construction methods
+-->
-The list of default construction methods includes the following:
+ <para>
+
+ An <literal>environment</literal>
+ is a collection of values that
+ can affect how a program executes.
+ &SCons; distinguishes between three
+ different types of environments
+ that can affect the behavior of &SCons; itself
+ (subject to the configuration in the &SConscript; files),
+ as well as the compilers and other tools it executes:
+
+ </para>
+
+ <variablelist>
+
+ <varlistentry>
+ <term>External Environment</term>
+
+ <listitem>
+ <para>
+
+ The <literal>external environment</literal>
+ is the set of variables in the user's environment
+ at the time the user runs &SCons.
+ These variables are available within the &SConscript; files
+ through the Python <literal>os.environ</literal> dictionary.
+ See <xref linkend="sect-external-environments"></xref>, below.
+
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>&ConsEnv;</term>
+
+ <listitem>
+ <para>
+
+ A &consenv;
+ is a distinct object creating within
+ a &SConscript; file and
+ and which contains values that
+ affect how &SCons; decides
+ what action to use to build a target,
+ and even to define which targets
+ should be built from which sources.
+ One of the most powerful features of &SCons;
+ is the ability to create multiple &consenvs;,
+ including the ability to clone a new, customized
+ &consenv; from an existing &consenv;.
+ See <xref linkend="sect-construction-environments"></xref>, below.
+
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Execution Environment</term>
+
+ <listitem>
+ <para>
+
+ An <literal>execution environment</literal>
+ is the values that &SCons; sets
+ when executing an external
+ command (such as a compiler or linker)
+ to build one or more targets.
+ Note that this is not the same as
+ the <literal>external environment</literal>
+ (see above).
+ See <xref linkend="sect-execution-environments"></xref>, below.
+
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+ <para>
+
+ Unlike &Make;, &SCons; does not automatically
+ copy or import values between different environments
+ (with the exception of explicit clones of &consenvs,
+ which inherit values from their parent).
+ This is a deliberate design choice
+ to make sure that builds are,
+ by default, repeatable regardless of
+ the values in the user's external environment.
+ This avoids a whole class of problems with builds
+ where a developer's local build works
+ because a custom variable setting
+ causes a different comiler or build option to be used,
+ but the checked-in change breaks the official build
+ because it uses different environment variable settings.
+
+ </para>
+
+ <para>
+
+ Note that the &SConscript; writer can
+ easily arrange for variables to be
+ copied or imported between environments,
+ and this is often very useful
+ (or even downright necessary)
+ to make it easy for developers
+ to customize the build in appropriate ways.
+ The point is <emphasis>not</emphasis>
+ that copying variables between different environments
+ is evil and must always be avoided.
+ Instead, it should be up to the
+ implementer of the build system
+ to make conscious choices
+ about how and when to import
+ a variable from one environment to another,
+ making informed decisions about
+ striking the right balance
+ between making the build
+ repeatable on the one hand
+ and convenient to use on the other.
+
+ </para>
+
+ <section id="sect-external-environments">
+ <title>Using Values From the External Environment</title>
+
+ <para>
+
+ The <literal>external environment</literal>
+ variable settings that
+ the user has in force
+ when executing &SCons;
+ are available through the normal Python
+ <envar>os.environ</envar>
+ dictionary.
+ This means that you must add an
+ <literal>import os</literal> statuement
+ to any &SConscript; file
+ in which you want to use
+ values from the user's external environment.
+
+ </para>
+
+ <scons_example name="ex1">
+ <file name="SConstruct" printme="1">
+ import os
+ </file>
+ <file name="foo.c">
+ int main() { }
+ </file>
+ </scons_example>
+ <para>
+
+ More usefully, you can use the
+ <envar>os.environ</envar>
+ dictionary in your &SConscript;
+ files to initialize &consenvs;
+ with values from the user's external environment.
+ See the next section,
+ <xref linkend="sect-construction-environments"></xref>,
+ for information on how to do this.
+
+ </para>
+
+ </section>
+
+ <section id="sect-construction-environments">
+ <title>Construction Environments</title>
+
+ <para>
+
+ It is rare that all of the software in a large,
+ complicated system needs to be built the same way.
+ For example, different source files may need different options
+ enabled on the command line,
+ or different executable programs need to be linked
+ with different libraries.
+ &SCons; accommodates these different build
+ requirements by allowing you to create and
+ configure multiple &consenvs;
+ that control how the software is built.
+ A &consenv; is an object
+ that has a number of associated
+ &consvars;, each with a name and a value.
+ (A construction environment also has an attached
+ set of &Builder; methods,
+ about which we'll learn more later.)
+
+ </para>
+
+ <section>
+ <title>Creating a &ConsEnv;: the &Environment; Function</title>
-=head2 The C<new> constructor
+ <para>
+
+ A &consenv; is created by the &Environment; method:
-The C<new> method is a Perl object constructor. That is, it is not invoked
-via a reference to an existing construction environment B<reference>, but,
-rather statically, using the name of the Perl B<package> where the
-constructor is defined. The method is invoked like this:
+ </para>
- $env = new cons(<overrides>);
+ <sconstruct>
+ env = Environment()
+ </sconstruct>
+
+ <para>
-The environment you get back is blessed into the package C<cons>, which
-means that it will have associated with it the default methods described
-below. Individual construction variables can be overridden by providing
-name/value pairs in an override list. Note that to override any command
-environment variable (i.e. anything under C<ENV>), you will have to override
-all of them. You can get around this difficulty by using the C<copy> method
-on an existing construction environment.
+ By default, &SCons; initializes every
+ new construction environment
+ with a set of &consvars;
+ based on the tools that it finds on your system,
+ plus the default set of builder methods
+ necessary for using those tools.
+ The construction variables
+ are initialized with values describing
+ the C compiler,
+ the Fortran compiler,
+ the linker,
+ etc.,
+ as well as the command lines to invoke them.
+
+ </para>
+
+ <para>
+
+ When you initialize a construction environment
+ you can set the values of the
+ environment's &consvars;
+ to control how a program is built.
+ For example:
+ </para>
-=head2 The C<clone> method
+ <scons_example name="ex1">
+ <file name="SConstruct" printme="1">
+ env = Environment(CC = 'gcc',
+ CCFLAGS = '-O2')
-The C<clone> method creates a clone of an existing construction environment,
-and can be called as in the following example:
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ int main() { }
+ </file>
+ </scons_example>
- $env2 = $env1->clone(<overrides>);
+ <para>
-You can provide overrides in the usual manner to create a different
-environment from the original. If you just want a new name for the same
-environment (which may be helpful when exporting environments to existing
-components), you can just use simple assignment.
+ The construction environment in this example
+ is still initialized with the same default
+ construction variable values,
+ except that the user has explicitly specified use of the
+ GNU C compiler &gcc;,
+ and further specifies that the <literal>-O2</literal>
+ (optimization level two)
+ flag should be used when compiling the object file.
+ In other words, the explicit initializations of
+ &cv-link-CC; and &cv-link-CCFLAGS;
+ override the default values in the newly-created
+ construction environment.
+ So a run from this example would look like:
+ </para>
-=head2 The C<copy> method
+ <scons_output example="ex1">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
-The C<copy> method extracts the externally defined construction variables
-from an environment and returns them as a list of name/value
-pairs. Overrides can also be provided, in which case, the overridden values
-will be returned, as appropriate. The returned list can be assigned to a
-hash, as shown in the prototype, below, but it can also be manipulated in
-other ways:
+ </section>
- %env = $env1->copy(<overrides>);
+ <section>
+ <title>Fetching Values From a &ConsEnv;</title>
+
+ <para>
+
+ You can fetch individual construction variables
+ using the normal syntax
+ for accessing individual named items in a Python dictionary:
-The value of C<ENV>, which is itself a hash, is also copied to a new hash,
-so this may be changed without fear of affecting the original
-environment. So, for example, if you really want to override just the
-C<PATH> variable in the default environment, you could do the following:
+ </para>
- %cons = new cons()->copy();
- $cons{ENV}{PATH} = "<your path here>";
- $cons = new cons(%cons);
+ <scons_example name="ex6">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ print "CC is:", env['CC']
+ </file>
+ </scons_example>
-This will leave anything else that might be in the default execution
-environment undisturbed.
+ <para>
--->
+ This example &SConstruct; file doesn't build anything,
+ but because it's actually a Python script,
+ it will print the value of &cv-link-CC; for us:
- <para>
-
- It is rare that all of the software in a large,
- complicated system needs to be built the same way.
- For example, different source files may need different options
- enabled on the command line,
- or different executable programs need to be linked
- with different libraries.
- &SCons; accommodates these different build
- requirements by allowing you to create and
- configure multiple &consenvs;
- that control how the software is built.
- Technically, a &consenv; is an object
- that has a number of associated
- &consvars;, each with a name and a value.
- (A construction environment also has an attached
- set of &Builder; methods,
- about which we'll learn more later.)
-
- </para>
-
- <para>
-
- A &consenv; is created by the &Environment; method:
-
- </para>
-
- <sconstruct>
- env = Environment()
- </sconstruct>
-
- <para>
-
- By default, &SCons; initializes every
- new construction environment
- with a set of &consvars;
- based on the tools that it finds on your system,
- plus the default set of builder methods
- necessary for using those tools.
- The construction variables
- are initialized with values describing
- the C compiler,
- the Fortran compiler,
- the linker,
- etc.,
- as well as the command lines to invoke them.
-
- </para>
-
- <para>
-
- When you initialize a construction environment
- you can set the values of the
- environment's &consvars;
- to control how a program is built.
- For example:
-
- </para>
-
- <scons_example name="ex1">
- <file name="SConstruct" printme="1">
- env = Environment(CC = 'gcc',
- CCFLAGS = '-O2')
-
- env.Program('foo.c')
- </file>
- <file name="foo.c">
- int main() { }
- </file>
- </scons_example>
-
- <para>
-
- The construction environment in this example
- is still initialized with the same default
- construction variable values,
- except that the user has explicitly specified use of the
- GNU C compiler &gcc;,
- and further specifies that the <literal>-O2</literal>
- (optimization level two)
- flag should be used when compiling the object file.
- In other words, the explicit initializations of
- &cv-link-CC; and &cv-link-CCFLAGS;
- override the default values in the newly-created
- construction environment.
- So a run from this example would look like:
-
- </para>
-
- <scons_output example="ex1">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
-
- <section>
- <title>Multiple &ConsEnvs;</title>
-
- <para>
-
- The real advantage of construction environments
- is that you can create as many different construction
- environments as you need,
- each tailored to a different way to build
- some piece of software or other file.
- If, for example, we need to build
- one program with the <literal>-O2</literal> flag
- and another with the <literal>-g</literal> (debug) flag,
- we would do this like so:
-
- </para>
-
- <scons_example name="ex2">
- <file name="SConstruct" printme="1">
- opt = Environment(CCFLAGS = '-O2')
- dbg = Environment(CCFLAGS = '-g')
+ </para>
- opt.Program('foo', 'foo.c')
+ <scons_output example="ex6">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
- dbg.Program('bar', 'bar.c')
- </file>
- <file name="foo.c">
- int main() { }
- </file>
- <file name="bar.c">
- int main() { }
- </file>
- </scons_example>
+ <para>
- <scons_output example="ex2">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ A construction environment, however,
+ is actually an object with associated methods, etc.
+ If you want to have direct access to only the
+ dictionary of construction variables,
+ you can fetch this using the &Dictionary; method:
- <para>
+ </para>
- We can even use multiple construction environments to build
- multiple versions of a single program.
- If you do this by simply trying to use the
- &b-link-Program; builder with both environments, though,
- like this:
+ <scons_example name="ex6b">
+ <file name="SConstruct" printme="1">
+ env = Environment(FOO = 'foo', BAR = 'bar')
+ dict = env.Dictionary()
+ for key in ['OBJSUFFIX', 'LIBSUFFIX', 'PROGSUFFIX']:
+ print "key = %s, value = %s" % (key, dict[key])
+ </file>
+ </scons_Example>
- </para>
+ <para>
- <scons_example name="ex3">
- <file name="SConstruct" printme="1">
- opt = Environment(CCFLAGS = '-O2')
- dbg = Environment(CCFLAGS = '-g')
+ This &SConstruct; file
+ will print the specified dictionary items for us on POSIX
+ systems as follows:
- opt.Program('foo', 'foo.c')
+ </para>
- dbg.Program('foo', 'foo.c')
- </file>
- <file name="foo.c">
- int main() { }
- </file>
- </scons_example>
+ <scons_output example="ex6b" os="posix">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
- <para>
+ <para>
- Then &SCons; generates the following error:
+ And on Windows:
- </para>
+ </para>
- <scons_output example="ex3">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
-
- <para>
-
- This is because the two &b-Program; calls have
- each implicitly told &SCons; to generate an object file named
- <filename>foo.o</filename>,
- one with a &cv-link-CCFLAGS; value of
- <literal>-O2</literal>
- and one with a &cv-link-CCFLAGS; value of
- <literal>-g</literal>.
- &SCons; can't just decide that one of them
- should take precedence over the other,
- so it generates the error.
- To avoid this problem,
- we must explicitly specify
- that each environment compile
- <filename>foo.c</filename>
- to a separately-named object file
- using the &b-link-Object; builder, like so:
-
- </para>
-
- <scons_example name="ex4">
- <file name="SConstruct" printme="1">
- opt = Environment(CCFLAGS = '-O2')
- dbg = Environment(CCFLAGS = '-g')
+ <scons_output example="ex6b" os="win32">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
- o = opt.Object('foo-opt', 'foo.c')
- opt.Program(o)
+ <para>
- d = dbg.Object('foo-dbg', 'foo.c')
- dbg.Program(d)
- </file>
- <file name="foo.c">
- int main() { }
- </file>
- </scons_example>
+ If you want to loop and print the values of
+ all of the construction variables in a construction environment,
+ the Python code to do that in sorted order might look something like:
- <para>
+ </para>
- Notice that each call to the &b-Object; builder
- returns a value,
- an internal &SCons; object that
- represents the object file that will be built.
- We then use that object
- as input to the &b-Program; builder.
- This avoids having to specify explicitly
- the object file name in multiple places,
- and makes for a compact, readable
- &SConstruct; file.
- Our &SCons; output then looks like:
+ <sconstruct>
+ env = Environment()
+ dict = env.Dictionary()
+ keys = dict.keys()
+ keys.sort()
+ for key in keys:
+ print "construction variable = '%s', value = '%s'" % (key, dict[key])
+ </sconstruct>
- </para>
+ </section>
- <scons_output example="ex4">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ <section>
+ <title>Expanding Values From a &ConsEnv;: the &subst; Method</title>
- </section>
+ <para>
- <section>
- <title>Copying &ConsEnvs;</title>
+ Another way to get information from
+ a construction environment.
+ is to use the &subst; method
+ on a string containing <literal>$</literal> expansions
+ of construction variable names.
+ As a simple example,
+ the example from the previous
+ section that used
+ <literal>env['CC']</literal>
+ to fetch the value of &cv-link-CC;
+ could also be written as:
- <para>
+ </para>
- Sometimes you want more than one construction environment
- to share the same values for one or more variables.
- Rather than always having to repeat all of the common
- variables when you create each construction environment,
- you can use the &Clone; method
- to create a copy of a construction environment.
+ <sconstruct>
+ env = Environment()
+ print "CC is:", env.subst('$CC')
+ </sconstruct>
- </para>
+ <para>
- <para>
+ One advantage of using
+ &subst; to expand strings is
+ that construction variables
+ in the result get re-expanded until
+ there are no expansions left in the string.
+ So a simple fetch of a value like
+ &cv-link-CCCOM;:
- Like the &Environment; call that creates a construction environment,
- the &Clone; method takes &consvar; assignments,
- which will override the values in the copied construction environment.
- For example, suppose we want to use &gcc;
- to create three versions of a program,
- one optimized, one debug, and one with neither.
- We could do this by creating a "base" construction environment
- that sets &cv-link-CC; to &gcc;,
- and then creating two copies,
- one which sets &cv-link-CCFLAGS; for optimization
- and the other which sets &cv-CCFLAGS; for debugging:
+ </para>
- </para>
+ <sconstruct>
+ env = Environment(CCFLAGS = '-DFOO')
+ print "CCCOM is:", env['CCCOM']
+ </sconstruct>
- <scons_example name="ex5">
- <file name="SConstruct" printme="1">
- env = Environment(CC = 'gcc')
- opt = env.Clone(CCFLAGS = '-O2')
- dbg = env.Clone(CCFLAGS = '-g')
+ <para>
- env.Program('foo', 'foo.c')
+ Will print the unexpanded value of &cv-CCCOM;,
+ showing us the construction
+ variables that still need to be expanded:
- o = opt.Object('foo-opt', 'foo.c')
- opt.Program(o)
+ </para>
- d = dbg.Object('foo-dbg', 'foo.c')
- dbg.Program(d)
- </file>
- <file name="foo.c">
- int main() { }
- </file>
- </scons_example>
+ <screen>
+ % <userinput>scons -Q</userinput>
+ CCCOM is: $CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES
+ scons: `.' is up to date.
+ </screen>
- <para>
+ <para>
- Then our output would look like:
+ Calling the &subst; method on <varname>$CCOM</varname>,
+ however:
- </para>
+ </para>
- <scons_output example="ex5">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ <sconstruct>
+ env = Environment(CCFLAGS = '-DFOO')
+ print "CCCOM is:", env.subst('$CCCOM')
+ </sconstruct>
- </section>
+ <para>
- <section>
- <title>Fetching Values From a &ConsEnv;</title>
+ Will recursively expand all of
+ the construction variables prefixed
+ with <literal>$</literal> (dollar signs),
+ showing us the final output:
- <para>
+ </para>
- You can fetch individual construction variables
- using the normal syntax
- for accessing individual named items in a Python dictionary:
+ <screen>
+ % <userinput>scons -Q</userinput>
+ CCCOM is: gcc -DFOO -c -o
+ scons: `.' is up to date.
+ </screen>
- </para>
+ <para>
- <scons_example name="ex6">
- <file name="SConstruct" printme="1">
- env = Environment()
- print "CC is:", env['CC']
- </file>
- </scons_example>
+ Note that because we're not expanding this
+ in the context of building something
+ there are no target or source files
+ for &cv-link-TARGET; and &cv-link-SOURCES; to expand.
- <para>
+ </para>
- This example &SConstruct; file doesn't build anything,
- but because it's actually a Python script,
- it will print the value of &cv-link-CC; for us:
+ </section>
- </para>
+ <section>
+ <title>Controlling the Default &ConsEnv;: the &DefaultEnvironment; Function</title>
- <scons_output example="ex6">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ <para>
- <para>
+ All of the &Builder; functions that we've introduced so far,
+ like &Program; and &Library;,
+ actually use a default &consenv;
+ that contains settings
+ for the various compilers
+ and other tools that
+ &SCons; configures by default,
+ or otherwise knows about
+ and has discovered on your system.
+ The goal of the default construction environment
+ is to make many configurations to "just work"
+ to build software using
+ readily available tools
+ with a minimum of configuration changes.
- A construction environment, however,
- is actually an object with associated methods, etc.
- If you want to have direct access to only the
- dictionary of construction variables,
- you can fetch this using the &Dictionary; method:
+ </para>
- </para>
+ <para>
- <scons_example name="ex6b">
- <file name="SConstruct" printme="1">
- env = Environment(FOO = 'foo', BAR = 'bar')
- dict = env.Dictionary()
- for key in ['OBJSUFFIX', 'LIBSUFFIX', 'PROGSUFFIX']:
- print "key = %s, value = %s" % (key, dict[key])
- </file>
- </scons_Example>
+ You can, however, control the settings
+ in the default contstruction environment
+ by using the &DefaultEnvironment; function
+ to initialize various settings:
- <para>
+ </para>
- This &SConstruct; file
- will print the specified dictionary items for us on POSIX
- systems as follows:
+ <sconstruct>
- </para>
+ DefaultEnvironment(CC = '/usr/local/bin/gcc')
- <scons_output example="ex6b" os="posix">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ </sconstruct>
- <para>
+ <para>
- And on Windows:
+ When configured as above,
+ all calls to the &Program;
+ or &Object; Builder
+ will build object files with the
+ <filename>/usr/local/bin/gcc</filename>
+ compiler.
- </para>
+ </para>
- <scons_output example="ex6b" os="win32">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ <para>
- <para>
+ Note that the &DefaultEnvironment; function
+ returns the initialized
+ default construction environment object,
+ which can then be manipulated like any
+ other construction environment.
+ So the following
+ would be equivalent to the
+ previous example,
+ setting the &cv-CC;
+ variable to <filename>/usr/local/bin/gcc</filename>
+ but as a separate step after
+ the default construction environment has been initialized:
- If you want to loop through and print the values of
- all of the construction variables in a construction environment,
- the Python code to do that in sorted order might look something like:
+ </para>
- </para>
+ <sconstruct>
- <sconstruct>
- env = Environment()
- dict = env.Dictionary()
- keys = dict.keys()
- keys.sort()
- for key in keys:
- print "construction variable = '%s', value = '%s'" % (key, dict[key])
- </sconstruct>
+ env = DefaultEnvironment()
+ env['CC'] = '/usr/local/bin/gcc'
- </section>
+ </sconstruct>
- <section>
- <title>Expanding Values From a &ConsEnv;</title>
+ <para>
- <para>
+ One very common use of the &DefaultEnvironment; function
+ is to speed up &SCons; initialization.
+ As part of trying to make most default
+ configurations "just work,"
+ &SCons; will actually
+ search the local system for installed
+ compilers and other utilities.
+ This search can take time,
+ especially on systems with
+ slow or networked file systems.
+ If you know which compiler(s) and/or
+ other utilities you want to configure,
+ you can control the search
+ that &SCons; performs
+ by specifying some specific
+ tool modules with which to
+ initialize the default construction environment:
- Another way to get information from
- a construction environment.
- is to use the &subst; method
- on a string containing $-expansions
- of construction variable names.
- As a simple example,
- the example from the previous
- section that used
- <literal>env['CC']</literal>
- to fetch the value of &cv-link-CC;
- could also be written as:
+ </para>
- </para>
+ <sconstruct>
- <sconstruct>
- env = Environment()
- print "CC is:", env.subst('$CC')
- </sconstruct>
+ env = DefaultEnvironment(tools = ['gcc', 'gnulink'],
+ CC = '/usr/local/bin/gcc')
+
+ </sconstruct>
+
+ <para>
+
+ So the above example would tell &SCons;
+ to explicitly configure the default environment
+ to use its normal GNU Compiler and GNU Linker settings
+ (without having to search for them,
+ or any other utilities for that matter),
+ and specifically to use the compiler found at
+ <filename>/usr/local/bin/gcc</filename>.
+
+ </para>
+
+ </section>
+
+ <section>
+ <title>Multiple &ConsEnvs;</title>
- <para>
+ <para>
- The real advantage of using
- &subst; to expand strings is
- that construction variables
- in the result get
- re-expanded until
- there are no expansions left in the string.
- So a simple fetch of a value like
- &cv-link-CCCOM;:
+ The real advantage of construction environments
+ is that you can create as many different construction
+ environments as you need,
+ each tailored to a different way to build
+ some piece of software or other file.
+ If, for example, we need to build
+ one program with the <literal>-O2</literal> flag
+ and another with the <literal>-g</literal> (debug) flag,
+ we would do this like so:
+
+ </para>
+
+ <scons_example name="ex2">
+ <file name="SConstruct" printme="1">
+ opt = Environment(CCFLAGS = '-O2')
+ dbg = Environment(CCFLAGS = '-g')
+
+ opt.Program('foo', 'foo.c')
+
+ dbg.Program('bar', 'bar.c')
+ </file>
+ <file name="foo.c">
+ int main() { }
+ </file>
+ <file name="bar.c">
+ int main() { }
+ </file>
+ </scons_example>
+
+ <scons_output example="ex2">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ We can even use multiple construction environments to build
+ multiple versions of a single program.
+ If you do this by simply trying to use the
+ &b-link-Program; builder with both environments, though,
+ like this:
+
+ </para>
+
+ <scons_example name="ex3">
+ <file name="SConstruct" printme="1">
+ opt = Environment(CCFLAGS = '-O2')
+ dbg = Environment(CCFLAGS = '-g')
+
+ opt.Program('foo', 'foo.c')
+
+ dbg.Program('foo', 'foo.c')
+ </file>
+ <file name="foo.c">
+ int main() { }
+ </file>
+ </scons_example>
+
+ <para>
+
+ Then &SCons; generates the following error:
+
+ </para>
+
+ <scons_output example="ex3">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ This is because the two &b-Program; calls have
+ each implicitly told &SCons; to generate an object file named
+ <filename>foo.o</filename>,
+ one with a &cv-link-CCFLAGS; value of
+ <literal>-O2</literal>
+ and one with a &cv-link-CCFLAGS; value of
+ <literal>-g</literal>.
+ &SCons; can't just decide that one of them
+ should take precedence over the other,
+ so it generates the error.
+ To avoid this problem,
+ we must explicitly specify
+ that each environment compile
+ <filename>foo.c</filename>
+ to a separately-named object file
+ using the &b-link-Object; builder, like so:
+
+ </para>
+
+ <scons_example name="ex4">
+ <file name="SConstruct" printme="1">
+ opt = Environment(CCFLAGS = '-O2')
+ dbg = Environment(CCFLAGS = '-g')
+
+ o = opt.Object('foo-opt', 'foo.c')
+ opt.Program(o)
+
+ d = dbg.Object('foo-dbg', 'foo.c')
+ dbg.Program(d)
+ </file>
+ <file name="foo.c">
+ int main() { }
+ </file>
+ </scons_example>
+
+ <para>
+
+ Notice that each call to the &b-Object; builder
+ returns a value,
+ an internal &SCons; object that
+ represents the object file that will be built.
+ We then use that object
+ as input to the &b-Program; builder.
+ This avoids having to specify explicitly
+ the object file name in multiple places,
+ and makes for a compact, readable
+ &SConstruct; file.
+ Our &SCons; output then looks like:
+
+ </para>
+
+ <scons_output example="ex4">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ </section>
+
+ <section>
+ <title>Making Copies of &ConsEnvs;: the &Clone; Method</title>
- </para>
+ <para>
- <sconstruct>
- env = Environment(CCFLAGS = '-DFOO')
- print "CCCOM is:", env['CCCOM']
- </sconstruct>
+ Sometimes you want more than one construction environment
+ to share the same values for one or more variables.
+ Rather than always having to repeat all of the common
+ variables when you create each construction environment,
+ you can use the &Clone; method
+ to create a copy of a construction environment.
+
+ </para>
- <para>
+ <para>
+
+ Like the &Environment; call that creates a construction environment,
+ the &Clone; method takes &consvar; assignments,
+ which will override the values in the copied construction environment.
+ For example, suppose we want to use &gcc;
+ to create three versions of a program,
+ one optimized, one debug, and one with neither.
+ We could do this by creating a "base" construction environment
+ that sets &cv-link-CC; to &gcc;,
+ and then creating two copies,
+ one which sets &cv-link-CCFLAGS; for optimization
+ and the other which sets &cv-CCFLAGS; for debugging:
- Will print the unexpanded value of &cv-CCCOM;,
- showing us the construction
- variables that still need to be expanded:
+ </para>
- </para>
+ <scons_example name="ex5">
+ <file name="SConstruct" printme="1">
+ env = Environment(CC = 'gcc')
+ opt = env.Clone(CCFLAGS = '-O2')
+ dbg = env.Clone(CCFLAGS = '-g')
+
+ env.Program('foo', 'foo.c')
+
+ o = opt.Object('foo-opt', 'foo.c')
+ opt.Program(o)
+
+ d = dbg.Object('foo-dbg', 'foo.c')
+ dbg.Program(d)
+ </file>
+ <file name="foo.c">
+ int main() { }
+ </file>
+ </scons_example>
+
+ <para>
+
+ Then our output would look like:
+
+ </para>
+
+ <scons_output example="ex5">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ </section>
+
+ <section>
+ <title>Replacing Values: the &Replace; Method</title>
+
+ <para>
+
+ You can replace existing construction variable values
+ using the &Replace; method:
+
+ </para>
+
+ <scons_example name="Replace1">
+ <file name="SConstruct" printme="1">
+ env = Environment(CCFLAGS = '-DDEFINE1')
+ env.Replace(CCFLAGS = '-DDEFINE2')
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ int main() { }
+ </file>
+ </scons_example>
+
+ <para>
+
+ The replacing value
+ (<literal>-DDEFINE2</literal> in the above example)
+ completely replaces the value in the
+ construction environment:
- <screen>
- % <userinput>scons -Q</userinput>
- CCCOM is: $CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES
- scons: `.' is up to date.
- </screen>
+ </para>
- <para>
+ <scons_output example="Replace1">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
- Calling the &subst; method on <varname>$CCOM</varname>,
- however:
+ <para>
- </para>
+ You can safely call &Replace;
+ for construction variables that
+ don't exist in the construction environment:
+
+ </para>
- <sconstruct>
- env = Environment(CCFLAGS = '-DFOO')
- print "CCCOM is:", env.subst('$CCCOM')
- </sconstruct>
+ <scons_example name="Replace-nonexistent">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ env.Replace(NEW_VARIABLE = 'xyzzy')
+ print "NEW_VARIABLE =", env['NEW_VARIABLE']
+ </file>
+ </scons_example>
- <para>
+ <para>
+
+ In this case,
+ the construction variable simply
+ gets added to the construction environment:
+
+ </para>
+
+ <scons_output example="Replace-nonexistent">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
- Will recursively expand all of
- the $-prefixed construction variables,
- showing us the final output:
+ <para>
- </para>
+ Because the variables
+ aren't expanded until the construction environment
+ is actually used to build the targets,
+ and because &SCons; function and method calls
+ are order-independent,
+ the last replacement "wins"
+ and is used to build all targets,
+ regardless of the order in which
+ the calls to Replace() are
+ interspersed with calls to
+ builder methods:
- <screen>
- % <userinput>scons -Q</userinput>
- CCCOM is: gcc -DFOO -c -o
- scons: `.' is up to date.
- </screen>
+ </para>
- <para>
+ <scons_example name="Replace2">
+ <file name="SConstruct" printme="1">
+ env = Environment(CCFLAGS = '-DDEFINE1')
+ print "CCFLAGS =", env['CCFLAGS']
+ env.Program('foo.c')
- (Note that because we're not expanding this
- in the context of building something
- there are no target or source files
- for &cv-link-TARGET; and &cv-link-SOURCES; to expand.)
+ env.Replace(CCFLAGS = '-DDEFINE2')
+ print "CCFLAGS =", env['CCFLAGS']
+ env.Program('bar.c')
+ </file>
+ <file name="foo.c">
+ int main() { }
+ </file>
+ <file name="bar.c">
+ int main() { }
+ </file>
+ </scons_example>
- </para>
+ <para>
- </section>
+ The timing of when the replacement
+ actually occurs relative
+ to when the targets get built
+ becomes apparent
+ if we run &scons; without the <literal>-Q</literal>
+ option:
- <section>
- <title>Modifying a &ConsEnv;</title>
+ </para>
+
+ <scons_output example="Replace2">
+ <scons_output_command>scons</scons_output_command>
+ </scons_output>
+
+ <para>
- <para>
+ Because the replacement occurs while
+ the &SConscript; files are being read,
+ the &cv-link-CCFLAGS;
+ variable has already been set to
+ <literal>-DDEFINE2</literal>
+ by the time the &foo_o; target is built,
+ even though the call to the &Replace;
+ method does not occur until later in
+ the &SConscript; file.
- &SCons; provides various methods that
- support modifying existing values in a construction environment.
+ </para>
- </para>
+ </section>
- <section>
- <title>Replacing Values in a &ConsEnv;</title>
+ <section>
+ <title>Setting Values Only If They're Not Already Defined: the &SetDefault; Method</title>
- <para>
+ <para>
- You can replace existing construction variable values
- using the &Replace; method:
+ Sometimes it's useful to be able to specify
+ that a construction variable should be
+ set to a value only if the construction environment
+ does not already have that variable defined
+ You can do this with the &SetDefault; method,
+ which behaves similarly to the <function>set_default</function>
+ method of Python dictionary objects:
- </para>
+ </para>
- <scons_example name="Replace1">
- <file name="SConstruct" printme="1">
- env = Environment(CCFLAGS = '-DDEFINE1')
- env.Replace(CCFLAGS = '-DDEFINE2')
- env.Program('foo.c')
- </file>
- <file name="foo.c">
- int main() { }
- </file>
- </scons_example>
+ <sconstruct>
+ env.SetDefault(SPECIAL_FLAG = '-extra-option')
+ </sconstruct>
- <para>
+ <para>
- The replacing value
- (<literal>-DDEFINE2</literal> in the above example)
- completely replaces the value in the
- construction environment:
+ This is especially useful
+ when writing your own <literal>Tool</literal> modules
+ to apply variables to construction environments.
+ <!--
+ See <xref linkend="chap-tool-modules"></xref>
+ for more information about writing
+ Tool modules.
+ -->
- </para>
+ </para>
- <scons_output example="Replace1">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ </section>
- <para>
+ <section>
+ <title>Appending to the End of Values: the &Append; Method</title>
- You can safely call &Replace;
- for construction variables that
- don't exist in the construction environment:
+ <para>
- </para>
+ You can append a value to
+ an existing construction variable
+ using the &Append; method:
- <scons_example name="Replace-nonexistent">
- <file name="SConstruct" printme="1">
- env = Environment()
- env.Replace(NEW_VARIABLE = 'xyzzy')
- print "NEW_VARIABLE =", env['NEW_VARIABLE']
- </file>
- </scons_example>
+ </para>
- <para>
+ <scons_example name="ex8">
+ <file name="SConstruct" printme="1">
+ env = Environment(CCFLAGS = ['-DMY_VALUE'])
+ env.Append(CCFLAGS = ['-DLAST'])
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ int main() { }
+ </file>
+ </scons_example>
- In this case,
- the construction variable simply
- gets added to the construction environment:
+ <para>
- </para>
+ &SCons; then supplies both the <literal>-DMY_VALUE</literal> and
+ <literal>-DLAST</literal> flags when compiling the object file:
- <scons_output example="Replace-nonexistent">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ </para>
- <para>
+ <scons_output example="ex8">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
- Because the variables
- aren't expanded until the construction environment
- is actually used to build the targets,
- and because &SCons; function and method calls
- are order-independent,
- the last replacement "wins"
- and is used to build all targets,
- regardless of the order in which
- the calls to Replace() are
- interspersed with calls to
- builder methods:
+ <para>
- </para>
+ If the construction variable doesn't already exist,
+ the &Append; method will create it:
- <scons_example name="Replace2">
- <file name="SConstruct" printme="1">
- env = Environment(CCFLAGS = '-DDEFINE1')
- print "CCFLAGS =", env['CCFLAGS']
- env.Program('foo.c')
+ </para>
- env.Replace(CCFLAGS = '-DDEFINE2')
- print "CCFLAGS =", env['CCFLAGS']
- env.Program('bar.c')
- </file>
- <file name="foo.c">
- int main() { }
- </file>
- <file name="bar.c">
- int main() { }
- </file>
- </scons_example>
+ <scons_example name="Append-nonexistent">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ env.Append(NEW_VARIABLE = 'added')
+ print "NEW_VARIABLE =", env['NEW_VARIABLE']
+ </file>
+ </scons_example>
- <para>
+ <para>
- The timing of when the replacement
- actually occurs relative
- to when the targets get built
- becomes apparent
- if we run &scons; without the <literal>-Q</literal>
- option:
+ Which yields:
- </para>
+ </para>
- <scons_output example="Replace2">
- <scons_output_command>scons</scons_output_command>
- </scons_output>
+ <scons_output example="Append-nonexistent">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
- <para>
+ <para>
- Because the replacement occurs while
- the &SConscript; files are being read,
- the &cv-link-CCFLAGS;
- variable has already been set to
- <literal>-DDEFINE2</literal>
- by the time the &foo_o; target is built,
- even though the call to the &Replace;
- method does not occur until later in
- the &SConscript; file.
+ Note that the &Append; function tries to be "smart"
+ about how the new value is appended to the old value.
+ If both are strings, the previous and new strings
+ are simply concatenated.
+ Similarly, if both are lists,
+ the lists are concatenated.
+ If, however, one is a string and the other is a list,
+ the string is added as a new element to the list.
- </para>
+ </para>
- </section>
+ </section>
- <!--
+ <section>
+ <title>Appending Unique Values: the &AppendUnique; Method</title>
- <section>
- <title>Setting Values Only If They're Not Already Defined</title>
+ <para>
- <para>
+ Some times it's useful to add a new value
+ only if the existing construction variable
+ doesn't already contain the value.
+ This can be done using the &AppendUnique; method:
- XXX SetDefault()
+ </para>
- </para>
+ <sconstruct>
+ env.AppendUnique(CCFLAGS=['-g'])
+ </sconstruct>
- </section>
+ <para>
- -->
+ In the above example,
+ the <literal>-g</literal> would be added
+ only if the &cv-CCFLAGS; variable
+ does not already contain a <literal>-g</literal> value.
- <section>
- <title>Appending to the End of Values in a &ConsEnv;</title>
+ </para>
- <para>
+ </section>
- You can append a value to
- an existing construction variable
- using the &Append; method:
+ <section>
+ <title>Appending to the Beginning of Values: the &Prepend; Method</title>
- </para>
+ <para>
- <scons_example name="ex8">
- <file name="SConstruct" printme="1">
- env = Environment(CCFLAGS = '-DMY_VALUE')
- env.Append(CCFLAGS = ' -DLAST')
- env.Program('foo.c')
- </file>
- <file name="foo.c">
- int main() { }
- </file>
- </scons_example>
+ You can append a value to the beginning of
+ an existing construction variable
+ using the &Prepend; method:
- <para>
+ </para>
- &SCons; then supplies both the <literal>-DMY_VALUE</literal> and
- <literal>-DLAST</literal> flags when compiling the object file:
+ <scons_example name="ex9">
+ <file name="SConstruct" printme="1">
+ env = Environment(CCFLAGS = ['-DMY_VALUE'])
+ env.Prepend(CCFLAGS = ['-DFIRST'])
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ int main() { }
+ </file>
+ </scons_example>
- </para>
+ <para>
- <scons_output example="ex8">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ &SCons; then supplies both the <literal>-DFIRST</literal> and
+ <literal>-DMY_VALUE</literal> flags when compiling the object file:
- <para>
+ </para>
- If the construction variable doesn't already exist,
- the &Append; method will create it:
+ <scons_output example="ex9">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
- </para>
+ <para>
- <scons_example name="Append-nonexistent">
- <file name="SConstruct" printme="1">
- env = Environment()
- env.Append(NEW_VARIABLE = 'added')
- print "NEW_VARIABLE =", env['NEW_VARIABLE']
- </file>
- </scons_example>
+ If the construction variable doesn't already exist,
+ the &Prepend; method will create it:
- <para>
+ </para>
- Which yields:
+ <scons_example name="Prepend-nonexistent">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ env.Prepend(NEW_VARIABLE = 'added')
+ print "NEW_VARIABLE =", env['NEW_VARIABLE']
+ </file>
+ </scons_example>
- </para>
+ <para>
- <scons_output example="Append-nonexistent">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ Which yields:
- <!--
+ </para>
- XXX AppendUnique()
+ <scons_output example="Prepend-nonexistent">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
- -->
+ <para>
- </section>
+ Like the &Append; function,
+ the &Prepend; function tries to be "smart"
+ about how the new value is appended to the old value.
+ If both are strings, the previous and new strings
+ are simply concatenated.
+ Similarly, if both are lists,
+ the lists are concatenated.
+ If, however, one is a string and the other is a list,
+ the string is added as a new element to the list.
- <section>
- <title>Appending to the Beginning of Values in a &ConsEnv;</title>
+ </para>
- <para>
+ </section>
- You can append a value to the beginning of
- an existing construction variable
- using the &Prepend; method:
+ <section>
+ <title>Prepending Unique Values: the &PrependUnique; Method</title>
- </para>
+ <para>
- <scons_example name="ex9">
- <file name="SConstruct" printme="1">
- env = Environment(CCFLAGS = '-DMY_VALUE')
- env.Prepend(CCFLAGS = '-DFIRST ')
- env.Program('foo.c')
- </file>
- <file name="foo.c">
- int main() { }
- </file>
- </scons_example>
+ Some times it's useful to add a new value
+ to the beginning of a construction variable
+ only if the existing value
+ doesn't already contain the to-be-added value.
+ This can be done using the &PrependUnique; method:
- <para>
+ </para>
- &SCons; then supplies both the <literal>-DFIRST</literal> and
- <literal>-DMY_VALUE</literal> flags when compiling the object file:
+ <sconstruct>
+ env.PrependUnique(CCFLAGS=['-g'])
+ </sconstruct>
- </para>
+ <para>
- <scons_output example="ex9">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ In the above example,
+ the <literal>-g</literal> would be added
+ only if the &cv-CCFLAGS; variable
+ does not already contain a <literal>-g</literal> value.
- <para>
+ </para>
- If the construction variable doesn't already exist,
- the &Prepend; method will create it:
+ </section>
- </para>
+ </section>
- <scons_example name="Prepend-nonexistent">
- <file name="SConstruct" printme="1">
- env = Environment()
- env.Prepend(NEW_VARIABLE = 'added')
- print "NEW_VARIABLE =", env['NEW_VARIABLE']
- </file>
- </scons_example>
+ <section id="sect-execution-environments">
+ <title>Controlling the Execution Environment for Issued Commands</title>
+
+ <para>
+
+ When &SCons; builds a target file,
+ it does not execute the commands with
+ the same external environment
+ that you used to execute &SCons;.
+ Instead, it uses the dictionary
+ stored in the &cv-link-ENV; construction variable
+ as the external environment
+ for executing commands.
- <para>
+ </para>
- Which yields:
+ <para>
- </para>
+ The most important ramification of this behavior
+ is that the &PATH; environment variable,
+ which controls where the operating system
+ will look for commands and utilities,
+ is not the same as in the external environment
+ from which you called &SCons;.
+ This means that &SCons; will not, by default,
+ necessarily find all of the tools
+ that you can execute from the command line.
- <scons_output example="Prepend-nonexistent">
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
+ </para>
- <!--
+ <para>
- XXX PrependUnique()
+ The default value of the &PATH; environment variable
+ on a POSIX system
+ is <literal>/usr/local/bin:/bin:/usr/bin</literal>.
+ The default value of the &PATH; environment variable
+ on a Windows system comes from the Windows registry
+ value for the command interpreter.
+ If you want to execute any commands--compilers, linkers, etc.--that
+ are not in these default locations,
+ you need to set the &PATH; value
+ in the &cv-ENV; dictionary
+ in your construction environment.
- -->
+ </para>
- </section>
+ <para>
- <!--
+ The simplest way to do this is to initialize explicitly
+ the value when you create the construction environment;
+ this is one way to do that:
- <section>
- <title>Adding to Values in the Execution Environment</title>
+ </para>
- <para>
+ <sconstruct>
+ path = ['/usr/local/bin', '/bin', '/usr/bin']
+ env = Environment(ENV = {'PATH' : path})
+ </sconstruct>
- XXX AppendENVPath()
+ <para>
- XXX PrependENVPath()
+ Assign a dictionary to the &cv-ENV;
+ construction variable in this way
+ completely resets the external environment
+ so that the only variable that will be
+ set when external commands are executed
+ will be the &PATH; value.
+ If you want to use the rest of
+ the values in &cv-ENV; and only
+ set the value of &PATH;,
+ the most straightforward way is probably:
- </para>
+ </para>
- </section>
+ <sconstruct>
+ env['ENV']['PATH'] = ['/usr/local/bin', '/bin', '/usr/bin']
+ </sconstruct>
- -->
+ <para>
- </section>
+ Note that &SCons; does allow you to define
+ the directories in the &PATH; in a string,
+ separated by the pathname-separator character
+ for your system (':' on POSIX systems, ';' on Windows):
+
+ </para>
+
+ <sconstruct>
+ env['ENV']['PATH'] = '/usr/local/bin:/bin:/usr/bin'
+ </sconstruct>
+
+ <para>
+
+ But doing so makes your &SConscript; file less portable,
+ (although in this case that may not be a huge concern
+ since the directories you list are likley system-specific, anyway).
+
+ </para>
+
+ <!--
+
+ <scons_example name="ex1">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ env.Command('foo', [], '__ROOT__/usr/bin/printenv.py')
+ </file>
+ <file name="__ROOT__/usr/bin/printenv.py" chmod="0755">
+ #!/usr/bin/env python
+ import os
+ import sys
+ if len(sys.argv) > 1:
+ keys = sys.argv[1:]
+ else:
+ keys = os.environ.keys()
+ keys.sort()
+ for key in keys:
+ print " " + key + "=" + os.environ[key]
+ </file>
+ </scons_example>
+
+ <para>
+
+ </para>
+
+ <scons_output example="ex1">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <section>
+ <title>Propagating &PATH; From the External Environment</title>
+
+ <para>
+
+ You may want to propagate the external &PATH;
+ to the execution environment for commands.
+ You do this by initializing the &PATH;
+ variable with the &PATH; value from
+ the <literal>os.environ</literal>
+ dictionary,
+ which is Python's way of letting you
+ get at the external environment:
+
+ </para>
+
+ <sconstruct>
+ import os
+ env = Environment(ENV = {'PATH' : os.environ['PATH']})
+ </sconstruct>
+
+ <para>
+
+ Alternatively, you may find it easier
+ to just propagate the entire external
+ environment to the execution environment
+ for commands.
+ This is simpler to code than explicity
+ selecting the &PATH; value:
+
+ </para>
+
+ <sconstruct>
+ import os
+ env = Environment(ENV = os.environ)
+ </sconstruct>
+
+ <para>
+
+ Either of these will guarantee that
+ &SCons; will be able to execute
+ any command that you can execute from the command line.
+ The drawback is that the build can behave
+ differently if it's run by people with
+ different &PATH; values in their environment--for example,
+ if both the <literal>/bin</literal> and
+ <literal>/usr/local/bin</literal> directories
+ have different &cc; commands,
+ then which one will be used to compile programs
+ will depend on which directory is listed
+ first in the user's &PATH; variable.
+
+ </para>
+
+ </section>
+
+ <section>
+ <title>Adding to <varname>PATH</varname> Values in the Execution Environment</title>
+
+ <para>
+
+ One of the most common requirements
+ for manipulating a variable in the execution environment
+ is to add one or more custom directories to a search
+ like the <envar>$PATH</envar> variable on Linux or POSIX systems,
+ or the <envar>%PATH%</envar> variable on Windows,
+ so that a locally-installed compiler or other utility
+ can be found when &SCons; tries to execute it to update a target.
+ &SCons; provides &PrependENVPath; and &AppendENVPath; functions
+ to make adding things to execution variables convenient.
+ You call these functions by specifying the variable
+ to which you want the value added,
+ and then value itself.
+ So to add some <filename>/usr/local</filename> directories
+ to the <envar>$PATH</envar> and <envar>$LIB</envar> variables,
+ you might:
+
+ </para>
+
+ <sconstruct>
+ env = Environment(ENV = os.environ)
+ env.PrependENVPath('PATH', '/usr/local/bin')
+ env.AppendENVPath('LIB', '/usr/local/lib')
+ </sconstruct>
+
+ <para>
+
+ Note that the added values are strings,
+ and if you want to add multiple directories to
+ a variable like <envar>$PATH</envar>,
+ you must include the path separate character
+ (<literal>:</literal> on Linux or POSIX,
+ <literal>;</literal> on Windows)
+ in the string.
+
+ </para>
+
+ </section>
+
+ </section>
<!--
- __COPYRIGHT__
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
- KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ __COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-->
Construction variables from a construction environment are expanded
by preceding the keyword with a C<%> (percent sign):
- Construction variables:
+ Construction variables:
XYZZY => 'abracadabra',
- The string: "The magic word is: %XYZZY!"
- expands to: "The magic word is: abracadabra!"
+ The string: "The magic word is: %XYZZY!"
+ expands to: "The magic word is: abracadabra!"
A construction variable name may be surrounded by C<{> and C<}> (curly
braces), which are stripped as part of the expansion. This can
sometimes be necessary to separate a variable expansion from trailing
alphanumeric characters:
- Construction variables:
+ Construction variables:
OPT => 'value1',
OPTION => 'value2',
- The string: "%OPT %{OPT}ION %OPTION %{OPTION}"
- expands to: "value1 value1ION value2 value2"
+ The string: "%OPT %{OPT}ION %OPTION %{OPTION}"
+ expands to: "value1 value1ION value2 value2"
Construction variable expansion is recursive, that is, a string
containing C<%->expansions after substitution will be re-expanded until
no further substitutions can be made:
- Construction variables:
+ Construction variables:
STRING => 'The result is: %FOO',
FOO => '%BAR',
BAR => 'final value',
- The string: "The string says: %STRING"
- expands to: "The string says: The result is: final value"
+ The string: "The string says: %STRING"
+ expands to: "The string says: The result is: final value"
If a construction variable is not defined in an environment, then the
null string is substituted:
- Construction variables:
+ Construction variables:
FOO => 'value1',
BAR => 'value2',
- The string: "%FOO <%NO_VARIABLE> %BAR"
- expands to: "value1 <> value2"
+ The string: "%FOO <%NO_VARIABLE> %BAR"
+ expands to: "value1 <> value2"
A doubled C<%%> will be replaced by a single C<%>:
- The string: "Here is a percent sign: %%"
- expands to: "Here is a percent sign: %"
+ The string: "Here is a percent sign: %%"
+ expands to: "Here is a percent sign: %"
=head2 Default construction variables
When you specify no arguments when creating a new construction
environment:
- $env = new cons();
+ $env = new cons();
Cons creates a reference to a new, default construction
environment. This contains a number of construction variables and some
methods. At the present writing, the default construction variables on a
UNIX system are:
- CC => 'cc',
- CFLAGS => '',
- CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>',
- CXX => '%CC',
- CXXFLAGS => '%CFLAGS',
- CXXCOM => '%CXX %CXXFLAGS %_IFLAGS -c %< -o %>',
- INCDIRPREFIX => '-I',
- INCDIRSUFFIX => '',
- LINK => '%CXX',
- LINKCOM => '%LINK %LDFLAGS -o %> %< %_LDIRS %LIBS',
- LINKMODULECOM => '%LD -r -o %> %<',
- LIBDIRPREFIX => '-L',
- LIBDIRSUFFIX => '',
- AR => 'ar',
- ARFLAGS => 'r',
- ARCOM => ['%AR %ARFLAGS %> %<', '%RANLIB %>'],
- RANLIB => 'ranlib',
- AS => 'as',
- ASFLAGS => '',
- ASCOM => '%AS %ASFLAGS %< -o %>',
- LD => 'ld',
- LDFLAGS => '',
- PREFLIB => 'lib',
- SUFLIB => '.a',
- SUFLIBS => '.so:.a',
- SUFOBJ => '.o',
- SIGNATURE => [ '*' => 'build' ],
- ENV => { 'PATH' => '/bin:/usr/bin' },
+ CC => 'cc',
+ CFLAGS => '',
+ CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>',
+ CXX => '%CC',
+ CXXFLAGS => '%CFLAGS',
+ CXXCOM => '%CXX %CXXFLAGS %_IFLAGS -c %< -o %>',
+ INCDIRPREFIX => '-I',
+ INCDIRSUFFIX => '',
+ LINK => '%CXX',
+ LINKCOM => '%LINK %LDFLAGS -o %> %< %_LDIRS %LIBS',
+ LINKMODULECOM => '%LD -r -o %> %<',
+ LIBDIRPREFIX => '-L',
+ LIBDIRSUFFIX => '',
+ AR => 'ar',
+ ARFLAGS => 'r',
+ ARCOM => ['%AR %ARFLAGS %> %<', '%RANLIB %>'],
+ RANLIB => 'ranlib',
+ AS => 'as',
+ ASFLAGS => '',
+ ASCOM => '%AS %ASFLAGS %< -o %>',
+ LD => 'ld',
+ LDFLAGS => '',
+ PREFLIB => 'lib',
+ SUFLIB => '.a',
+ SUFLIBS => '.so:.a',
+ SUFOBJ => '.o',
+ SIGNATURE => [ '*' => 'build' ],
+ ENV => { 'PATH' => '/bin:/usr/bin' },
And on a Windows system (Windows NT), the default construction variables
are (unless the default rule style is set using the B<DefaultRules>
method):
- CC => 'cl',
- CFLAGS => '/nologo',
- CCCOM => '%CC %CFLAGS %_IFLAGS /c %< /Fo%>',
- CXXCOM => '%CXX %CXXFLAGS %_IFLAGS /c %< /Fo%>',
- INCDIRPREFIX => '/I',
- INCDIRSUFFIX => '',
- LINK => 'link',
- LINKCOM => '%LINK %LDFLAGS /out:%> %< %_LDIRS %LIBS',
- LINKMODULECOM => '%LD /r /o %> %<',
- LIBDIRPREFIX => '/LIBPATH:',
- LIBDIRSUFFIX => '',
- AR => 'lib',
- ARFLAGS => '/nologo ',
- ARCOM => "%AR %ARFLAGS /out:%> %<",
- RANLIB => '',
- LD => 'link',
- LDFLAGS => '/nologo ',
- PREFLIB => '',
- SUFEXE => '.exe',
- SUFLIB => '.lib',
- SUFLIBS => '.dll:.lib',
- SUFOBJ => '.obj',
- SIGNATURE => [ '*' => 'build' ],
+ CC => 'cl',
+ CFLAGS => '/nologo',
+ CCCOM => '%CC %CFLAGS %_IFLAGS /c %< /Fo%>',
+ CXXCOM => '%CXX %CXXFLAGS %_IFLAGS /c %< /Fo%>',
+ INCDIRPREFIX => '/I',
+ INCDIRSUFFIX => '',
+ LINK => 'link',
+ LINKCOM => '%LINK %LDFLAGS /out:%> %< %_LDIRS %LIBS',
+ LINKMODULECOM => '%LD /r /o %> %<',
+ LIBDIRPREFIX => '/LIBPATH:',
+ LIBDIRSUFFIX => '',
+ AR => 'lib',
+ ARFLAGS => '/nologo ',
+ ARCOM => "%AR %ARFLAGS /out:%> %<",
+ RANLIB => '',
+ LD => 'link',
+ LDFLAGS => '/nologo ',
+ PREFLIB => '',
+ SUFEXE => '.exe',
+ SUFLIB => '.lib',
+ SUFLIBS => '.dll:.lib',
+ SUFOBJ => '.obj',
+ SIGNATURE => [ '*' => 'build' ],
These variables are used by the various methods associated with the
environment. In particular, any method that ultimately invokes an external
files and arranges to derive, if necessary, the corresponding object
files:
- Objects $env 'foo.c', 'bar.c';
+ Objects $env 'foo.c', 'bar.c';
This will arrange to produce, if necessary, F<foo.o> and F<bar.o>. The
command invoked is simply C<%CCCOM>, which expands, through substitution,
those will be deleted from the list provided by C<%E<lt>>. Consider the
following command found in a F<Conscript> file in the F<test> directory:
- Command $env 'tgt', qw(foo bar baz), qq(
+ Command $env 'tgt', qw(foo bar baz), qq(
echo %< -i %1 > %>
echo %< -i %2 >> %>
echo %< -i %3 >> %>
- );
+ );
If F<tgt> needed to be updated, then this would result in the execution of
the following commands, assuming that no remapping has been established for
the F<test> directory:
- echo test/bar test/baz -i test/foo > test/tgt
- echo test/foo test/baz -i test/bar >> test/tgt
- echo test/foo test/bar -i test/baz >> test/tgt
+ echo test/bar test/baz -i test/foo > test/tgt
+ echo test/foo test/baz -i test/bar >> test/tgt
+ echo test/foo test/bar -i test/baz >> test/tgt
=back
Any of the above pseudo-variables may be followed immediately by one of
the following suffixes to select a portion of the expanded path name:
- :a the absolute path to the file name
- :b the directory plus the file name stripped of any suffix
- :d the directory
- :f the file name
- :s the file name suffix
- :F the file name stripped of any suffix
- :S the absolute path path to a Linked source file
+ :a the absolute path to the file name
+ :b the directory plus the file name stripped of any suffix
+ :d the directory
+ :f the file name
+ :s the file name suffix
+ :F the file name stripped of any suffix
+ :S the absolute path path to a Linked source file
Continuing with the above example, C<%E<lt>:f> would expand to C<foo bar baz>,
and C<%E<gt>:d> would expand to C<test>.
replace the contents of the brackets in the command line. For example,
given an existing input file named F<tgt.in>:
- @keywords = qw(foo bar baz);
- $env = new cons(X_COMMA => sub { join(",", @_) });
- Command $env 'tgt', 'tgt.in', qq(
+ @keywords = qw(foo bar baz);
+ $env = new cons(X_COMMA => sub { join(",", @_) });
+ Command $env 'tgt', 'tgt.in', qq(
echo '# Keywords: %[X_COMMA @keywords %]' > %>
cat %< >> %>
- );
+ );
This will execute:
- echo '# Keywords: foo,bar,baz' > tgt
- cat tgt.in >> tgt
+ echo '# Keywords: foo,bar,baz' > tgt
+ cat tgt.in >> tgt
=item %( %)
passed to the various construction methods according to the expansion
rules described above:
- $env = new cons(
+ $env = new cons(
DESTDIR => 'programs',
SRCDIR => 'src',
- );
- Program $env '%DESTDIR/hello', '%SRCDIR/hello.c';
+ );
+ Program $env '%DESTDIR/hello', '%SRCDIR/hello.c';
This allows for flexible configuration, through the construction
environment, of directory names, suffixes, etc.
-=head1 Default construction methods
+-->
-The list of default construction methods includes the following:
+ <para>
+
+ An <literal>environment</literal>
+ is a collection of values that
+ can affect how a program executes.
+ &SCons; distinguishes between three
+ different types of environments
+ that can affect the behavior of &SCons; itself
+ (subject to the configuration in the &SConscript; files),
+ as well as the compilers and other tools it executes:
+
+ </para>
+
+ <variablelist>
+
+ <varlistentry>
+ <term>External Environment</term>
+
+ <listitem>
+ <para>
+
+ The <literal>external environment</literal>
+ is the set of variables in the user's environment
+ at the time the user runs &SCons;.
+ These variables are available within the &SConscript; files
+ through the Python <literal>os.environ</literal> dictionary.
+ See <xref linkend="sect-external-environments"></xref>, below.
+
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>&ConsEnv;</term>
+
+ <listitem>
+ <para>
+
+ A &consenv;
+ is a distinct object creating within
+ a &SConscript; file and
+ and which contains values that
+ affect how &SCons; decides
+ what action to use to build a target,
+ and even to define which targets
+ should be built from which sources.
+ One of the most powerful features of &SCons;
+ is the ability to create multiple &consenvs;,
+ including the ability to clone a new, customized
+ &consenv; from an existing &consenv;.
+ See <xref linkend="sect-construction-environments"></xref>, below.
+
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Execution Environment</term>
+
+ <listitem>
+ <para>
+
+ An <literal>execution environment</literal>
+ is the values that &SCons; sets
+ when executing an external
+ command (such as a compiler or linker)
+ to build one or more targets.
+ Note that this is not the same as
+ the <literal>external environment</literal>
+ (see above).
+ See <xref linkend="sect-execution-environments"></xref>, below.
+
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+ <para>
+
+ Unlike &Make;, &SCons; does not automatically
+ copy or import values between different environments
+ (with the exception of explicit clones of &consenvs;,
+ which inherit values from their parent).
+ This is a deliberate design choice
+ to make sure that builds are,
+ by default, repeatable regardless of
+ the values in the user's external environment.
+ This avoids a whole class of problems with builds
+ where a developer's local build works
+ because a custom variable setting
+ causes a different comiler or build option to be used,
+ but the checked-in change breaks the official build
+ because it uses different environment variable settings.
+
+ </para>
+
+ <para>
+
+ Note that the &SConscript; writer can
+ easily arrange for variables to be
+ copied or imported between environments,
+ and this is often very useful
+ (or even downright necessary)
+ to make it easy for developers
+ to customize the build in appropriate ways.
+ The point is <emphasis>not</emphasis>
+ that copying variables between different environments
+ is evil and must always be avoided.
+ Instead, it should be up to the
+ implementer of the build system
+ to make conscious choices
+ about how and when to import
+ a variable from one environment to another,
+ making informed decisions about
+ striking the right balance
+ between making the build
+ repeatable on the one hand
+ and convenient to use on the other.
+
+ </para>
+
+ <section id="sect-external-environments">
+ <title>Using Values From the External Environment</title>
+
+ <para>
+
+ The <literal>external environment</literal>
+ variable settings that
+ the user has in force
+ when executing &SCons;
+ are available through the normal Python
+ <envar>os.environ</envar>
+ dictionary.
+ This means that you must add an
+ <literal>import os</literal> statuement
+ to any &SConscript; file
+ in which you want to use
+ values from the user's external environment.
+
+ </para>
+ <programlisting>
+ import os
+ </programlisting>
-=head2 The C<new> constructor
+ <para>
+
+ More usefully, you can use the
+ <envar>os.environ</envar>
+ dictionary in your &SConscript;
+ files to initialize &consenvs;
+ with values from the user's external environment.
+ See the next section,
+ <xref linkend="sect-construction-environments"></xref>,
+ for information on how to do this.
+
+ </para>
+
+ </section>
+
+ <section id="sect-construction-environments">
+ <title>Construction Environments</title>
-The C<new> method is a Perl object constructor. That is, it is not invoked
-via a reference to an existing construction environment B<reference>, but,
-rather statically, using the name of the Perl B<package> where the
-constructor is defined. The method is invoked like this:
+ <para>
- $env = new cons(<overrides>);
+ It is rare that all of the software in a large,
+ complicated system needs to be built the same way.
+ For example, different source files may need different options
+ enabled on the command line,
+ or different executable programs need to be linked
+ with different libraries.
+ &SCons; accommodates these different build
+ requirements by allowing you to create and
+ configure multiple &consenvs;
+ that control how the software is built.
+ A &consenv; is an object
+ that has a number of associated
+ &consvars;, each with a name and a value.
+ (A construction environment also has an attached
+ set of &Builder; methods,
+ about which we'll learn more later.)
-The environment you get back is blessed into the package C<cons>, which
-means that it will have associated with it the default methods described
-below. Individual construction variables can be overridden by providing
-name/value pairs in an override list. Note that to override any command
-environment variable (i.e. anything under C<ENV>), you will have to override
-all of them. You can get around this difficulty by using the C<copy> method
-on an existing construction environment.
+ </para>
+ <section>
+ <title>Creating a &ConsEnv;: the &Environment; Function</title>
-=head2 The C<clone> method
+ <para>
-The C<clone> method creates a clone of an existing construction environment,
-and can be called as in the following example:
+ A &consenv; is created by the &Environment; method:
- $env2 = $env1->clone(<overrides>);
+ </para>
-You can provide overrides in the usual manner to create a different
-environment from the original. If you just want a new name for the same
-environment (which may be helpful when exporting environments to existing
-components), you can just use simple assignment.
+ <programlisting>
+ env = Environment()
+ </programlisting>
+ <para>
-=head2 The C<copy> method
+ By default, &SCons; initializes every
+ new construction environment
+ with a set of &consvars;
+ based on the tools that it finds on your system,
+ plus the default set of builder methods
+ necessary for using those tools.
+ The construction variables
+ are initialized with values describing
+ the C compiler,
+ the Fortran compiler,
+ the linker,
+ etc.,
+ as well as the command lines to invoke them.
-The C<copy> method extracts the externally defined construction variables
-from an environment and returns them as a list of name/value
-pairs. Overrides can also be provided, in which case, the overridden values
-will be returned, as appropriate. The returned list can be assigned to a
-hash, as shown in the prototype, below, but it can also be manipulated in
-other ways:
+ </para>
- %env = $env1->copy(<overrides>);
+ <para>
-The value of C<ENV>, which is itself a hash, is also copied to a new hash,
-so this may be changed without fear of affecting the original
-environment. So, for example, if you really want to override just the
-C<PATH> variable in the default environment, you could do the following:
+ When you initialize a construction environment
+ you can set the values of the
+ environment's &consvars;
+ to control how a program is built.
+ For example:
- %cons = new cons()->copy();
- $cons{ENV}{PATH} = "<your path here>";
- $cons = new cons(%cons);
+ </para>
-This will leave anything else that might be in the default execution
-environment undisturbed.
+ <programlisting>
+ import os
--->
+ env = Environment(CC = 'gcc',
+ CCFLAGS = '-O2')
- <para>
-
- It is rare that all of the software in a large,
- complicated system needs to be built the same way.
- For example, different source files may need different options
- enabled on the command line,
- or different executable programs need to be linked
- with different libraries.
- &SCons; accommodates these different build
- requirements by allowing you to create and
- configure multiple &consenvs;
- that control how the software is built.
- Technically, a &consenv; is an object
- that has a number of associated
- &consvars;, each with a name and a value.
- (A construction environment also has an attached
- set of &Builder; methods,
- about which we'll learn more later.)
-
- </para>
-
- <para>
-
- A &consenv; is created by the &Environment; method:
-
- </para>
-
- <programlisting>
- env = Environment()
- </programlisting>
-
- <para>
-
- By default, &SCons; initializes every
- new construction environment
- with a set of &consvars;
- based on the tools that it finds on your system,
- plus the default set of builder methods
- necessary for using those tools.
- The construction variables
- are initialized with values describing
- the C compiler,
- the Fortran compiler,
- the linker,
- etc.,
- as well as the command lines to invoke them.
-
- </para>
-
- <para>
-
- When you initialize a construction environment
- you can set the values of the
- environment's &consvars;
- to control how a program is built.
- For example:
-
- </para>
-
- <programlisting>
- env = Environment(CC = 'gcc',
- CCFLAGS = '-O2')
-
- env.Program('foo.c')
- </programlisting>
-
- <para>
-
- The construction environment in this example
- is still initialized with the same default
- construction variable values,
- except that the user has explicitly specified use of the
- GNU C compiler &gcc;,
- and further specifies that the <literal>-O2</literal>
- (optimization level two)
- flag should be used when compiling the object file.
- In other words, the explicit initializations of
- &cv-link-CC; and &cv-link-CCFLAGS;
- override the default values in the newly-created
- construction environment.
- So a run from this example would look like:
-
- </para>
-
- <screen>
- % <userinput>scons -Q</userinput>
- gcc -o foo.o -c -O2 foo.c
- gcc -o foo foo.o
- </screen>
-
- <section>
- <title>Multiple &ConsEnvs;</title>
-
- <para>
-
- The real advantage of construction environments
- is that you can create as many different construction
- environments as you need,
- each tailored to a different way to build
- some piece of software or other file.
- If, for example, we need to build
- one program with the <literal>-O2</literal> flag
- and another with the <literal>-g</literal> (debug) flag,
- we would do this like so:
-
- </para>
+ env.Program('foo.c')
+ </programlisting>
- <programlisting>
- opt = Environment(CCFLAGS = '-O2')
- dbg = Environment(CCFLAGS = '-g')
+ <para>
- opt.Program('foo', 'foo.c')
+ The construction environment in this example
+ is still initialized with the same default
+ construction variable values,
+ except that the user has explicitly specified use of the
+ GNU C compiler &gcc;,
+ and further specifies that the <literal>-O2</literal>
+ (optimization level two)
+ flag should be used when compiling the object file.
+ In other words, the explicit initializations of
+ &cv-link-CC; and &cv-link-CCFLAGS;
+ override the default values in the newly-created
+ construction environment.
+ So a run from this example would look like:
- dbg.Program('bar', 'bar.c')
- </programlisting>
+ </para>
- <screen>
- % <userinput>scons -Q</userinput>
- cc -o bar.o -c -g bar.c
- cc -o bar bar.o
- cc -o foo.o -c -O2 foo.c
- cc -o foo foo.o
- </screen>
+ <screen>
+ % <userinput>scons -Q</userinput>
+ gcc -o foo.o -c -O2 foo.c
+ gcc -o foo foo.o
+ </screen>
- <para>
+ </section>
- We can even use multiple construction environments to build
- multiple versions of a single program.
- If you do this by simply trying to use the
- &b-link-Program; builder with both environments, though,
- like this:
+ <section>
+ <title>Fetching Values From a &ConsEnv;</title>
- </para>
+ <para>
- <programlisting>
- opt = Environment(CCFLAGS = '-O2')
- dbg = Environment(CCFLAGS = '-g')
+ You can fetch individual construction variables
+ using the normal syntax
+ for accessing individual named items in a Python dictionary:
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ print "CC is:", env['CC']
+ </programlisting>
- opt.Program('foo', 'foo.c')
+ <para>
- dbg.Program('foo', 'foo.c')
- </programlisting>
+ This example &SConstruct; file doesn't build anything,
+ but because it's actually a Python script,
+ it will print the value of &cv-link-CC; for us:
- <para>
+ </para>
- Then &SCons; generates the following error:
+ <screen>
+ % <userinput>scons -Q</userinput>
+ CC is: cc
+ scons: `.' is up to date.
+ </screen>
- </para>
+ <para>
- <screen>
- % <userinput>scons -Q</userinput>
-
- scons: *** Two environments with different actions were specified for the same target: foo.o
- File "/home/my/project/SConstruct", line 6, in <module>
- </screen>
+ A construction environment, however,
+ is actually an object with associated methods, etc.
+ If you want to have direct access to only the
+ dictionary of construction variables,
+ you can fetch this using the &Dictionary; method:
- <para>
+ </para>
+
+ <programlisting>
+ env = Environment(FOO = 'foo', BAR = 'bar')
+ dict = env.Dictionary()
+ for key in ['OBJSUFFIX', 'LIBSUFFIX', 'PROGSUFFIX']:
+ print "key = %s, value = %s" % (key, dict[key])
+ </programlisting>
- This is because the two &b-Program; calls have
- each implicitly told &SCons; to generate an object file named
- <filename>foo.o</filename>,
- one with a &cv-link-CCFLAGS; value of
- <literal>-O2</literal>
- and one with a &cv-link-CCFLAGS; value of
- <literal>-g</literal>.
- &SCons; can't just decide that one of them
- should take precedence over the other,
- so it generates the error.
- To avoid this problem,
- we must explicitly specify
- that each environment compile
- <filename>foo.c</filename>
- to a separately-named object file
- using the &b-link-Object; builder, like so:
+ <para>
- </para>
+ This &SConstruct; file
+ will print the specified dictionary items for us on POSIX
+ systems as follows:
- <programlisting>
- opt = Environment(CCFLAGS = '-O2')
- dbg = Environment(CCFLAGS = '-g')
+ </para>
- o = opt.Object('foo-opt', 'foo.c')
- opt.Program(o)
+ <screen>
+ % <userinput>scons -Q</userinput>
+ key = OBJSUFFIX, value = .o
+ key = LIBSUFFIX, value = .a
+ key = PROGSUFFIX, value =
+ scons: `.' is up to date.
+ </screen>
- d = dbg.Object('foo-dbg', 'foo.c')
- dbg.Program(d)
- </programlisting>
+ <para>
- <para>
-
- Notice that each call to the &b-Object; builder
- returns a value,
- an internal &SCons; object that
- represents the object file that will be built.
- We then use that object
- as input to the &b-Program; builder.
- This avoids having to specify explicitly
- the object file name in multiple places,
- and makes for a compact, readable
- &SConstruct; file.
- Our &SCons; output then looks like:
-
- </para>
-
- <screen>
- % <userinput>scons -Q</userinput>
- cc -o foo-dbg.o -c -g foo.c
- cc -o foo-dbg foo-dbg.o
- cc -o foo-opt.o -c -O2 foo.c
- cc -o foo-opt foo-opt.o
- </screen>
-
- </section>
-
- <section>
- <title>Copying &ConsEnvs;</title>
-
- <para>
-
- Sometimes you want more than one construction environment
- to share the same values for one or more variables.
- Rather than always having to repeat all of the common
- variables when you create each construction environment,
- you can use the &Clone; method
- to create a copy of a construction environment.
-
- </para>
-
- <para>
-
- Like the &Environment; call that creates a construction environment,
- the &Clone; method takes &consvar; assignments,
- which will override the values in the copied construction environment.
- For example, suppose we want to use &gcc;
- to create three versions of a program,
- one optimized, one debug, and one with neither.
- We could do this by creating a "base" construction environment
- that sets &cv-link-CC; to &gcc;,
- and then creating two copies,
- one which sets &cv-link-CCFLAGS; for optimization
- and the other which sets &cv-CCFLAGS; for debugging:
-
- </para>
+ And on Windows:
- <programlisting>
- env = Environment(CC = 'gcc')
- opt = env.Clone(CCFLAGS = '-O2')
- dbg = env.Clone(CCFLAGS = '-g')
+ </para>
- env.Program('foo', 'foo.c')
+ <screen>
+ C:\><userinput>scons -Q</userinput>
+ key = OBJSUFFIX, value = .obj
+ key = LIBSUFFIX, value = .lib
+ key = PROGSUFFIX, value = .exe
+ scons: `.' is up to date.
+ </screen>
+
+ <para>
- o = opt.Object('foo-opt', 'foo.c')
- opt.Program(o)
+ If you want to loop and print the values of
+ all of the construction variables in a construction environment,
+ the Python code to do that in sorted order might look something like:
- d = dbg.Object('foo-dbg', 'foo.c')
- dbg.Program(d)
- </programlisting>
+ </para>
- <para>
+ <programlisting>
+ env = Environment()
+ dict = env.Dictionary()
+ keys = dict.keys()
+ keys.sort()
+ for key in keys:
+ print "construction variable = '%s', value = '%s'" % (key, dict[key])
+ </programlisting>
- Then our output would look like:
+ </section>
- </para>
+ <section>
+ <title>Expanding Values From a &ConsEnv;: the &subst; Method</title>
- <screen>
- % <userinput>scons -Q</userinput>
- gcc -o foo.o -c foo.c
- gcc -o foo foo.o
- gcc -o foo-dbg.o -c -g foo.c
- gcc -o foo-dbg foo-dbg.o
- gcc -o foo-opt.o -c -O2 foo.c
- gcc -o foo-opt foo-opt.o
- </screen>
+ <para>
- </section>
+ Another way to get information from
+ a construction environment.
+ is to use the &subst; method
+ on a string containing <literal>$</literal> expansions
+ of construction variable names.
+ As a simple example,
+ the example from the previous
+ section that used
+ <literal>env['CC']</literal>
+ to fetch the value of &cv-link-CC;
+ could also be written as:
- <section>
- <title>Fetching Values From a &ConsEnv;</title>
+ </para>
- <para>
+ <programlisting>
+ env = Environment()
+ print "CC is:", env.subst('$CC')
+ </programlisting>
- You can fetch individual construction variables
- using the normal syntax
- for accessing individual named items in a Python dictionary:
+ <para>
- </para>
+ One advantage of using
+ &subst; to expand strings is
+ that construction variables
+ in the result get re-expanded until
+ there are no expansions left in the string.
+ So a simple fetch of a value like
+ &cv-link-CCCOM;:
- <programlisting>
- env = Environment()
- print "CC is:", env['CC']
- </programlisting>
+ </para>
- <para>
+ <programlisting>
+ env = Environment(CCFLAGS = '-DFOO')
+ print "CCCOM is:", env['CCCOM']
+ </programlisting>
- This example &SConstruct; file doesn't build anything,
- but because it's actually a Python script,
- it will print the value of &cv-link-CC; for us:
+ <para>
- </para>
+ Will print the unexpanded value of &cv-CCCOM;,
+ showing us the construction
+ variables that still need to be expanded:
- <screen>
- % <userinput>scons -Q</userinput>
- CC is: cc
- scons: `.' is up to date.
- </screen>
+ </para>
- <para>
+ <screen>
+ % <userinput>scons -Q</userinput>
+ CCCOM is: $CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES
+ scons: `.' is up to date.
+ </screen>
- A construction environment, however,
- is actually an object with associated methods, etc.
- If you want to have direct access to only the
- dictionary of construction variables,
- you can fetch this using the &Dictionary; method:
+ <para>
- </para>
+ Calling the &subst; method on <varname>$CCOM</varname>,
+ however:
- <programlisting>
- env = Environment(FOO = 'foo', BAR = 'bar')
- dict = env.Dictionary()
- for key in ['OBJSUFFIX', 'LIBSUFFIX', 'PROGSUFFIX']:
- print "key = %s, value = %s" % (key, dict[key])
- </programlisting>
+ </para>
- <para>
+ <programlisting>
+ env = Environment(CCFLAGS = '-DFOO')
+ print "CCCOM is:", env.subst('$CCCOM')
+ </programlisting>
- This &SConstruct; file
- will print the specified dictionary items for us on POSIX
- systems as follows:
+ <para>
- </para>
+ Will recursively expand all of
+ the construction variables prefixed
+ with <literal>$</literal> (dollar signs),
+ showing us the final output:
- <screen>
- % <userinput>scons -Q</userinput>
- key = OBJSUFFIX, value = .o
- key = LIBSUFFIX, value = .a
- key = PROGSUFFIX, value =
- scons: `.' is up to date.
- </screen>
+ </para>
- <para>
+ <screen>
+ % <userinput>scons -Q</userinput>
+ CCCOM is: gcc -DFOO -c -o
+ scons: `.' is up to date.
+ </screen>
- And on Windows:
+ <para>
+
+ Note that because we're not expanding this
+ in the context of building something
+ there are no target or source files
+ for &cv-link-TARGET; and &cv-link-SOURCES; to expand.
- </para>
+ </para>
- <screen>
- C:\><userinput>scons -Q</userinput>
- key = OBJSUFFIX, value = .obj
- key = LIBSUFFIX, value = .lib
- key = PROGSUFFIX, value = .exe
- scons: `.' is up to date.
- </screen>
+ </section>
- <para>
+ <section>
+ <title>Controlling the Default &ConsEnv;: the &DefaultEnvironment; Function</title>
- If you want to loop through and print the values of
- all of the construction variables in a construction environment,
- the Python code to do that in sorted order might look something like:
+ <para>
- </para>
+ All of the &Builder; functions that we've introduced so far,
+ like &Program; and &Library;,
+ actually use a default &consenv;
+ that contains settings
+ for the various compilers
+ and other tools that
+ &SCons; configures by default,
+ or otherwise knows about
+ and has discovered on your system.
+ The goal of the default construction environment
+ is to make many configurations to "just work"
+ to build software using
+ readily available tools
+ with a minimum of configuration changes.
- <programlisting>
- env = Environment()
- dict = env.Dictionary()
- keys = dict.keys()
- keys.sort()
- for key in keys:
- print "construction variable = '%s', value = '%s'" % (key, dict[key])
- </programlisting>
+ </para>
- </section>
+ <para>
- <section>
- <title>Expanding Values From a &ConsEnv;</title>
+ You can, however, control the settings
+ in the default contstruction environment
+ by using the &DefaultEnvironment; function
+ to initialize various settings:
- <para>
+ </para>
- Another way to get information from
- a construction environment.
- is to use the &subst; method
- on a string containing $-expansions
- of construction variable names.
- As a simple example,
- the example from the previous
- section that used
- <literal>env['CC']</literal>
- to fetch the value of &cv-link-CC;
- could also be written as:
+ <programlisting>
- </para>
+ DefaultEnvironment(CC = '/usr/local/bin/gcc')
- <programlisting>
- env = Environment()
- print "CC is:", env.subst('$CC')
- </programlisting>
+ </programlisting>
- <para>
+ <para>
- The real advantage of using
- &subst; to expand strings is
- that construction variables
- in the result get
- re-expanded until
- there are no expansions left in the string.
- So a simple fetch of a value like
- &cv-link-CCCOM;:
+ When configured as above,
+ all calls to the &Program;
+ or &Object; Builder
+ will build object files with the
+ <filename>/usr/local/bin/gcc</filename>
+ compiler.
- </para>
+ </para>
- <programlisting>
- env = Environment(CCFLAGS = '-DFOO')
- print "CCCOM is:", env['CCCOM']
- </programlisting>
+ <para>
- <para>
+ Note that the &DefaultEnvironment; function
+ returns the initialized
+ default construction environment object,
+ which can then be manipulated like any
+ other construction environment.
+ So the following
+ would be equivalent to the
+ previous example,
+ setting the &cv-CC;
+ variable to <filename>/usr/local/bin/gcc</filename>
+ but as a separate step after
+ the default construction environment has been initialized:
- Will print the unexpanded value of &cv-CCCOM;,
- showing us the construction
- variables that still need to be expanded:
+ </para>
- </para>
+ <programlisting>
- <screen>
- % <userinput>scons -Q</userinput>
- CCCOM is: $CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES
- scons: `.' is up to date.
- </screen>
+ env = DefaultEnvironment()
+ env['CC'] = '/usr/local/bin/gcc'
- <para>
+ </programlisting>
- Calling the &subst; method on <varname>$CCOM</varname>,
- however:
+ <para>
- </para>
+ One very common use of the &DefaultEnvironment; function
+ is to speed up &SCons; initialization.
+ As part of trying to make most default
+ configurations "just work,"
+ &SCons; will actually
+ search the local system for installed
+ compilers and other utilities.
+ This search can take time,
+ especially on systems with
+ slow or networked file systems.
+ If you know which compiler(s) and/or
+ other utilities you want to configure,
+ you can control the search
+ that &SCons; performs
+ by specifying some specific
+ tool modules with which to
+ initialize the default construction environment:
- <programlisting>
- env = Environment(CCFLAGS = '-DFOO')
- print "CCCOM is:", env.subst('$CCCOM')
- </programlisting>
+ </para>
- <para>
+ <programlisting>
- Will recursively expand all of
- the $-prefixed construction variables,
- showing us the final output:
+ env = DefaultEnvironment(tools = ['gcc', 'gnulink'],
+ CC = '/usr/local/bin/gcc')
+
+ </programlisting>
+
+ <para>
- </para>
+ So the above example would tell &SCons;
+ to explicitly configure the default environment
+ to use its normal GNU Compiler and GNU Linker settings
+ (without having to search for them,
+ or any other utilities for that matter),
+ and specifically to use the compiler found at
+ <filename>/usr/local/bin/gcc</filename>.
- <screen>
- % <userinput>scons -Q</userinput>
- CCCOM is: gcc -DFOO -c -o
- scons: `.' is up to date.
- </screen>
+ </para>
- <para>
+ </section>
- (Note that because we're not expanding this
- in the context of building something
- there are no target or source files
- for &cv-link-TARGET; and &cv-link-SOURCES; to expand.)
+ <section>
+ <title>Multiple &ConsEnvs;</title>
- </para>
+ <para>
- </section>
+ The real advantage of construction environments
+ is that you can create as many different construction
+ environments as you need,
+ each tailored to a different way to build
+ some piece of software or other file.
+ If, for example, we need to build
+ one program with the <literal>-O2</literal> flag
+ and another with the <literal>-g</literal> (debug) flag,
+ we would do this like so:
- <section>
- <title>Modifying a &ConsEnv;</title>
+ </para>
+
+ <programlisting>
+ opt = Environment(CCFLAGS = '-O2')
+ dbg = Environment(CCFLAGS = '-g')
+
+ opt.Program('foo', 'foo.c')
+
+ dbg.Program('bar', 'bar.c')
+ </programlisting>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ cc -o bar.o -c -g bar.c
+ cc -o bar bar.o
+ cc -o foo.o -c -O2 foo.c
+ cc -o foo foo.o
+ </screen>
+
+ <para>
+
+ We can even use multiple construction environments to build
+ multiple versions of a single program.
+ If you do this by simply trying to use the
+ &b-link-Program; builder with both environments, though,
+ like this:
+
+ </para>
+
+ <programlisting>
+ opt = Environment(CCFLAGS = '-O2')
+ dbg = Environment(CCFLAGS = '-g')
+
+ opt.Program('foo', 'foo.c')
+
+ dbg.Program('foo', 'foo.c')
+ </programlisting>
+
+ <para>
+
+ Then &SCons; generates the following error:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+
+ scons: *** Two environments with different actions were specified for the same target: foo.o
+ File "/home/my/project/SConstruct", line 6, in <module>
+ </screen>
+
+ <para>
+
+ This is because the two &b-Program; calls have
+ each implicitly told &SCons; to generate an object file named
+ <filename>foo.o</filename>,
+ one with a &cv-link-CCFLAGS; value of
+ <literal>-O2</literal>
+ and one with a &cv-link-CCFLAGS; value of
+ <literal>-g</literal>.
+ &SCons; can't just decide that one of them
+ should take precedence over the other,
+ so it generates the error.
+ To avoid this problem,
+ we must explicitly specify
+ that each environment compile
+ <filename>foo.c</filename>
+ to a separately-named object file
+ using the &b-link-Object; builder, like so:
+
+ </para>
+
+ <programlisting>
+ opt = Environment(CCFLAGS = '-O2')
+ dbg = Environment(CCFLAGS = '-g')
- <para>
+ o = opt.Object('foo-opt', 'foo.c')
+ opt.Program(o)
- &SCons; provides various methods that
- support modifying existing values in a construction environment.
+ d = dbg.Object('foo-dbg', 'foo.c')
+ dbg.Program(d)
+ </programlisting>
- </para>
+ <para>
- <section>
- <title>Replacing Values in a &ConsEnv;</title>
+ Notice that each call to the &b-Object; builder
+ returns a value,
+ an internal &SCons; object that
+ represents the object file that will be built.
+ We then use that object
+ as input to the &b-Program; builder.
+ This avoids having to specify explicitly
+ the object file name in multiple places,
+ and makes for a compact, readable
+ &SConstruct; file.
+ Our &SCons; output then looks like:
- <para>
+ </para>
- You can replace existing construction variable values
- using the &Replace; method:
+ <screen>
+ % <userinput>scons -Q</userinput>
+ cc -o foo-dbg.o -c -g foo.c
+ cc -o foo-dbg foo-dbg.o
+ cc -o foo-opt.o -c -O2 foo.c
+ cc -o foo-opt foo-opt.o
+ </screen>
- </para>
+ </section>
- <programlisting>
- env = Environment(CCFLAGS = '-DDEFINE1')
- env.Replace(CCFLAGS = '-DDEFINE2')
- env.Program('foo.c')
- </programlisting>
+ <section>
+ <title>Making Copies of &ConsEnvs;: the &Clone; Method</title>
- <para>
+ <para>
- The replacing value
- (<literal>-DDEFINE2</literal> in the above example)
- completely replaces the value in the
- construction environment:
+ Sometimes you want more than one construction environment
+ to share the same values for one or more variables.
+ Rather than always having to repeat all of the common
+ variables when you create each construction environment,
+ you can use the &Clone; method
+ to create a copy of a construction environment.
- </para>
+ </para>
- <screen>
- % <userinput>scons -Q</userinput>
- cc -o foo.o -c -DDEFINE2 foo.c
- cc -o foo foo.o
- </screen>
+ <para>
- <para>
+ Like the &Environment; call that creates a construction environment,
+ the &Clone; method takes &consvar; assignments,
+ which will override the values in the copied construction environment.
+ For example, suppose we want to use &gcc;
+ to create three versions of a program,
+ one optimized, one debug, and one with neither.
+ We could do this by creating a "base" construction environment
+ that sets &cv-link-CC; to &gcc;,
+ and then creating two copies,
+ one which sets &cv-link-CCFLAGS; for optimization
+ and the other which sets &cv-CCFLAGS; for debugging:
- You can safely call &Replace;
- for construction variables that
- don't exist in the construction environment:
+ </para>
+
+ <programlisting>
+ env = Environment(CC = 'gcc')
+ opt = env.Clone(CCFLAGS = '-O2')
+ dbg = env.Clone(CCFLAGS = '-g')
+
+ env.Program('foo', 'foo.c')
+
+ o = opt.Object('foo-opt', 'foo.c')
+ opt.Program(o)
+
+ d = dbg.Object('foo-dbg', 'foo.c')
+ dbg.Program(d)
+ </programlisting>
+
+ <para>
+
+ Then our output would look like:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ gcc -o foo.o -c foo.c
+ gcc -o foo foo.o
+ gcc -o foo-dbg.o -c -g foo.c
+ gcc -o foo-dbg foo-dbg.o
+ gcc -o foo-opt.o -c -O2 foo.c
+ gcc -o foo-opt foo-opt.o
+ </screen>
- </para>
+ </section>
- <programlisting>
- env = Environment()
- env.Replace(NEW_VARIABLE = 'xyzzy')
- print "NEW_VARIABLE =", env['NEW_VARIABLE']
- </programlisting>
+ <section>
+ <title>Replacing Values: the &Replace; Method</title>
+
+ <para>
+
+ You can replace existing construction variable values
+ using the &Replace; method:
+
+ </para>
+
+ <programlisting>
+ env = Environment(CCFLAGS = '-DDEFINE1')
+ env.Replace(CCFLAGS = '-DDEFINE2')
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+ The replacing value
+ (<literal>-DDEFINE2</literal> in the above example)
+ completely replaces the value in the
+ construction environment:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ cc -o foo.o -c -DDEFINE2 foo.c
+ cc -o foo foo.o
+ </screen>
- <para>
+ <para>
- In this case,
- the construction variable simply
- gets added to the construction environment:
+ You can safely call &Replace;
+ for construction variables that
+ don't exist in the construction environment:
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ env.Replace(NEW_VARIABLE = 'xyzzy')
+ print "NEW_VARIABLE =", env['NEW_VARIABLE']
+ </programlisting>
+
+ <para>
- </para>
+ In this case,
+ the construction variable simply
+ gets added to the construction environment:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ NEW_VARIABLE = xyzzy
+ scons: `.' is up to date.
+ </screen>
+
+ <para>
- <screen>
- % <userinput>scons -Q</userinput>
- NEW_VARIABLE = xyzzy
- scons: `.' is up to date.
- </screen>
+ Because the variables
+ aren't expanded until the construction environment
+ is actually used to build the targets,
+ and because &SCons; function and method calls
+ are order-independent,
+ the last replacement "wins"
+ and is used to build all targets,
+ regardless of the order in which
+ the calls to Replace() are
+ interspersed with calls to
+ builder methods:
- <para>
+ </para>
- Because the variables
- aren't expanded until the construction environment
- is actually used to build the targets,
- and because &SCons; function and method calls
- are order-independent,
- the last replacement "wins"
- and is used to build all targets,
- regardless of the order in which
- the calls to Replace() are
- interspersed with calls to
- builder methods:
+ <programlisting>
+ env = Environment(CCFLAGS = '-DDEFINE1')
+ print "CCFLAGS =", env['CCFLAGS']
+ env.Program('foo.c')
- </para>
+ env.Replace(CCFLAGS = '-DDEFINE2')
+ print "CCFLAGS =", env['CCFLAGS']
+ env.Program('bar.c')
+ </programlisting>
- <programlisting>
- env = Environment(CCFLAGS = '-DDEFINE1')
- print "CCFLAGS =", env['CCFLAGS']
- env.Program('foo.c')
+ <para>
- env.Replace(CCFLAGS = '-DDEFINE2')
- print "CCFLAGS =", env['CCFLAGS']
- env.Program('bar.c')
- </programlisting>
+ The timing of when the replacement
+ actually occurs relative
+ to when the targets get built
+ becomes apparent
+ if we run &scons; without the <literal>-Q</literal>
+ option:
- <para>
+ </para>
- The timing of when the replacement
- actually occurs relative
- to when the targets get built
- becomes apparent
- if we run &scons; without the <literal>-Q</literal>
- option:
+ <screen>
+ % <userinput>scons</userinput>
+ scons: Reading SConscript files ...
+ CCFLAGS = -DDEFINE1
+ CCFLAGS = -DDEFINE2
+ scons: done reading SConscript files.
+ scons: Building targets ...
+ cc -o bar.o -c -DDEFINE2 bar.c
+ cc -o bar bar.o
+ cc -o foo.o -c -DDEFINE2 foo.c
+ cc -o foo foo.o
+ scons: done building targets.
+ </screen>
- </para>
+ <para>
- <screen>
- % <userinput>scons</userinput>
- scons: Reading SConscript files ...
- CCFLAGS = -DDEFINE1
- CCFLAGS = -DDEFINE2
- scons: done reading SConscript files.
- scons: Building targets ...
- cc -o bar.o -c -DDEFINE2 bar.c
- cc -o bar bar.o
- cc -o foo.o -c -DDEFINE2 foo.c
- cc -o foo foo.o
- scons: done building targets.
- </screen>
+ Because the replacement occurs while
+ the &SConscript; files are being read,
+ the &cv-link-CCFLAGS;
+ variable has already been set to
+ <literal>-DDEFINE2</literal>
+ by the time the &foo_o; target is built,
+ even though the call to the &Replace;
+ method does not occur until later in
+ the &SConscript; file.
- <para>
+ </para>
- Because the replacement occurs while
- the &SConscript; files are being read,
- the &cv-link-CCFLAGS;
- variable has already been set to
- <literal>-DDEFINE2</literal>
- by the time the &foo_o; target is built,
- even though the call to the &Replace;
- method does not occur until later in
- the &SConscript; file.
+ </section>
- </para>
+ <section>
+ <title>Setting Values Only If They're Not Already Defined: the &SetDefault; Method</title>
- </section>
+ <para>
- <!--
+ Sometimes it's useful to be able to specify
+ that a construction variable should be
+ set to a value only if the construction environment
+ does not already have that variable defined
+ You can do this with the &SetDefault; method,
+ which behaves similarly to the <function>set_default</function>
+ method of Python dictionary objects:
- <section>
- <title>Setting Values Only If They're Not Already Defined</title>
+ </para>
- <para>
+ <programlisting>
+ env.SetDefault(SPECIAL_FLAG = '-extra-option')
+ </programlisting>
- XXX SetDefault()
+ <para>
- </para>
+ This is especially useful
+ when writing your own <literal>Tool</literal> modules
+ to apply variables to construction environments.
+ <!--
+ See <xref linkend="chap-tool-modules"></xref>
+ for more information about writing
+ Tool modules.
+ -->
- </section>
+ </para>
- -->
+ </section>
- <section>
- <title>Appending to the End of Values in a &ConsEnv;</title>
+ <section>
+ <title>Appending to the End of Values: the &Append; Method</title>
- <para>
+ <para>
- You can append a value to
- an existing construction variable
- using the &Append; method:
+ You can append a value to
+ an existing construction variable
+ using the &Append; method:
- </para>
+ </para>
- <programlisting>
- env = Environment(CCFLAGS = '-DMY_VALUE')
- env.Append(CCFLAGS = ' -DLAST')
- env.Program('foo.c')
- </programlisting>
+ <programlisting>
+ env = Environment(CCFLAGS = ['-DMY_VALUE'])
+ env.Append(CCFLAGS = ['-DLAST'])
+ env.Program('foo.c')
+ </programlisting>
- <para>
+ <para>
- &SCons; then supplies both the <literal>-DMY_VALUE</literal> and
- <literal>-DLAST</literal> flags when compiling the object file:
+ &SCons; then supplies both the <literal>-DMY_VALUE</literal> and
+ <literal>-DLAST</literal> flags when compiling the object file:
- </para>
+ </para>
- <screen>
- % <userinput>scons -Q</userinput>
- cc -o foo.o -c -DMY_VALUE -DLAST foo.c
- cc -o foo foo.o
- </screen>
+ <screen>
+ % <userinput>scons -Q</userinput>
+ cc -o foo.o -c -DMY_VALUE -DLAST foo.c
+ cc -o foo foo.o
+ </screen>
- <para>
+ <para>
- If the construction variable doesn't already exist,
- the &Append; method will create it:
+ If the construction variable doesn't already exist,
+ the &Append; method will create it:
- </para>
+ </para>
- <programlisting>
- env = Environment()
- env.Append(NEW_VARIABLE = 'added')
- print "NEW_VARIABLE =", env['NEW_VARIABLE']
- </programlisting>
+ <programlisting>
+ env = Environment()
+ env.Append(NEW_VARIABLE = 'added')
+ print "NEW_VARIABLE =", env['NEW_VARIABLE']
+ </programlisting>
- <para>
+ <para>
- Which yields:
+ Which yields:
- </para>
+ </para>
- <screen>
- % <userinput>scons -Q</userinput>
- NEW_VARIABLE = added
- scons: `.' is up to date.
- </screen>
+ <screen>
+ % <userinput>scons -Q</userinput>
+ NEW_VARIABLE = added
+ scons: `.' is up to date.
+ </screen>
- <!--
+ <para>
- XXX AppendUnique()
+ Note that the &Append; function tries to be "smart"
+ about how the new value is appended to the old value.
+ If both are strings, the previous and new strings
+ are simply concatenated.
+ Similarly, if both are lists,
+ the lists are concatenated.
+ If, however, one is a string and the other is a list,
+ the string is added as a new element to the list.
- -->
+ </para>
- </section>
+ </section>
- <section>
- <title>Appending to the Beginning of Values in a &ConsEnv;</title>
+ <section>
+ <title>Appending Unique Values: the &AppendUnique; Method</title>
- <para>
+ <para>
- You can append a value to the beginning of
- an existing construction variable
- using the &Prepend; method:
+ Some times it's useful to add a new value
+ only if the existing construction variable
+ doesn't already contain the value.
+ This can be done using the &AppendUnique; method:
- </para>
+ </para>
- <programlisting>
- env = Environment(CCFLAGS = '-DMY_VALUE')
- env.Prepend(CCFLAGS = '-DFIRST ')
- env.Program('foo.c')
- </programlisting>
+ <programlisting>
+ env.AppendUnique(CCFLAGS=['-g'])
+ </programlisting>
- <para>
+ <para>
- &SCons; then supplies both the <literal>-DFIRST</literal> and
- <literal>-DMY_VALUE</literal> flags when compiling the object file:
+ In the above example,
+ the <literal>-g</literal> would be added
+ only if the &cv-CCFLAGS; variable
+ does not already contain a <literal>-g</literal> value.
- </para>
+ </para>
- <screen>
- % <userinput>scons -Q</userinput>
- cc -o foo.o -c -DFIRST -DMY_VALUE foo.c
- cc -o foo foo.o
- </screen>
+ </section>
- <para>
+ <section>
+ <title>Appending to the Beginning of Values: the &Prepend; Method</title>
- If the construction variable doesn't already exist,
- the &Prepend; method will create it:
+ <para>
- </para>
+ You can append a value to the beginning of
+ an existing construction variable
+ using the &Prepend; method:
- <programlisting>
- env = Environment()
- env.Prepend(NEW_VARIABLE = 'added')
- print "NEW_VARIABLE =", env['NEW_VARIABLE']
- </programlisting>
+ </para>
- <para>
+ <programlisting>
+ env = Environment(CCFLAGS = ['-DMY_VALUE'])
+ env.Prepend(CCFLAGS = ['-DFIRST'])
+ env.Program('foo.c')
+ </programlisting>
- Which yields:
+ <para>
- </para>
+ &SCons; then supplies both the <literal>-DFIRST</literal> and
+ <literal>-DMY_VALUE</literal> flags when compiling the object file:
- <screen>
- % <userinput>scons -Q</userinput>
- NEW_VARIABLE = added
- scons: `.' is up to date.
- </screen>
+ </para>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ cc -o foo.o -c -DFIRST -DMY_VALUE foo.c
+ cc -o foo foo.o
+ </screen>
+
+ <para>
+
+ If the construction variable doesn't already exist,
+ the &Prepend; method will create it:
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ env.Prepend(NEW_VARIABLE = 'added')
+ print "NEW_VARIABLE =", env['NEW_VARIABLE']
+ </programlisting>
+
+ <para>
+
+ Which yields:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ NEW_VARIABLE = added
+ scons: `.' is up to date.
+ </screen>
+
+ <para>
+
+ Like the &Append; function,
+ the &Prepend; function tries to be "smart"
+ about how the new value is appended to the old value.
+ If both are strings, the previous and new strings
+ are simply concatenated.
+ Similarly, if both are lists,
+ the lists are concatenated.
+ If, however, one is a string and the other is a list,
+ the string is added as a new element to the list.
+
+ </para>
+
+ </section>
+
+ <section>
+ <title>Prepending Unique Values: the &PrependUnique; Method</title>
+
+ <para>
+
+ Some times it's useful to add a new value
+ to the beginning of a construction variable
+ only if the existing value
+ doesn't already contain the to-be-added value.
+ This can be done using the &PrependUnique; method:
+
+ </para>
+
+ <programlisting>
+ env.PrependUnique(CCFLAGS=['-g'])
+ </programlisting>
+
+ <para>
- <!--
+ In the above example,
+ the <literal>-g</literal> would be added
+ only if the &cv-CCFLAGS; variable
+ does not already contain a <literal>-g</literal> value.
- XXX PrependUnique()
+ </para>
- -->
+ </section>
- </section>
+ </section>
- <!--
+ <section id="sect-execution-environments">
+ <title>Controlling the Execution Environment for Issued Commands</title>
- <section>
- <title>Adding to Values in the Execution Environment</title>
+ <para>
- <para>
+ When &SCons; builds a target file,
+ it does not execute the commands with
+ the same external environment
+ that you used to execute &SCons;.
+ Instead, it uses the dictionary
+ stored in the &cv-link-ENV; construction variable
+ as the external environment
+ for executing commands.
- XXX AppendENVPath()
+ </para>
- XXX PrependENVPath()
+ <para>
- </para>
+ The most important ramification of this behavior
+ is that the &PATH; environment variable,
+ which controls where the operating system
+ will look for commands and utilities,
+ is not the same as in the external environment
+ from which you called &SCons;.
+ This means that &SCons; will not, by default,
+ necessarily find all of the tools
+ that you can execute from the command line.
- </section>
+ </para>
- -->
+ <para>
- </section>
+ The default value of the &PATH; environment variable
+ on a POSIX system
+ is <literal>/usr/local/bin:/bin:/usr/bin</literal>.
+ The default value of the &PATH; environment variable
+ on a Windows system comes from the Windows registry
+ value for the command interpreter.
+ If you want to execute any commands--compilers, linkers, etc.--that
+ are not in these default locations,
+ you need to set the &PATH; value
+ in the &cv-ENV; dictionary
+ in your construction environment.
+
+ </para>
+
+ <para>
+
+ The simplest way to do this is to initialize explicitly
+ the value when you create the construction environment;
+ this is one way to do that:
+
+ </para>
+
+ <programlisting>
+ path = ['/usr/local/bin', '/bin', '/usr/bin']
+ env = Environment(ENV = {'PATH' : path})
+ </programlisting>
+
+ <para>
+
+ Assign a dictionary to the &cv-ENV;
+ construction variable in this way
+ completely resets the external environment
+ so that the only variable that will be
+ set when external commands are executed
+ will be the &PATH; value.
+ If you want to use the rest of
+ the values in &cv-ENV; and only
+ set the value of &PATH;,
+ the most straightforward way is probably:
+
+ </para>
+
+ <programlisting>
+ env['ENV']['PATH'] = ['/usr/local/bin', '/bin', '/usr/bin']
+ </programlisting>
+
+ <para>
+
+ Note that &SCons; does allow you to define
+ the directories in the &PATH; in a string,
+ separated by the pathname-separator character
+ for your system (':' on POSIX systems, ';' on Windows):
+
+ </para>
+
+ <programlisting>
+ env['ENV']['PATH'] = '/usr/local/bin:/bin:/usr/bin'
+ </programlisting>
+
+ <para>
+
+ But doing so makes your &SConscript; file less portable,
+ (although in this case that may not be a huge concern
+ since the directories you list are likley system-specific, anyway).
+
+ </para>
+
+ <!--
+
+ <scons_example name="ex1">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ env.Command('foo', [], '__ROOT__/usr/bin/printenv.py')
+ </file>
+ <file name="__ROOT__/usr/bin/printenv.py" chmod="0755">
+ #!/usr/bin/env python
+ import os
+ import sys
+ if len(sys.argv) > 1:
+ keys = sys.argv[1:]
+ else:
+ keys = os.environ.keys()
+ keys.sort()
+ for key in keys:
+ print " " + key + "=" + os.environ[key]
+ </file>
+ </scons_example>
+
+ <para>
+
+ </para>
+
+ <scons_output example="ex1">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <section>
+ <title>Propagating &PATH; From the External Environment</title>
+
+ <para>
+
+ You may want to propagate the external &PATH;
+ to the execution environment for commands.
+ You do this by initializing the &PATH;
+ variable with the &PATH; value from
+ the <literal>os.environ</literal>
+ dictionary,
+ which is Python's way of letting you
+ get at the external environment:
+
+ </para>
+
+ <programlisting>
+ import os
+ env = Environment(ENV = {'PATH' : os.environ['PATH']})
+ </programlisting>
+
+ <para>
+
+ Alternatively, you may find it easier
+ to just propagate the entire external
+ environment to the execution environment
+ for commands.
+ This is simpler to code than explicity
+ selecting the &PATH; value:
+
+ </para>
+
+ <programlisting>
+ import os
+ env = Environment(ENV = os.environ)
+ </programlisting>
+
+ <para>
+
+ Either of these will guarantee that
+ &SCons; will be able to execute
+ any command that you can execute from the command line.
+ The drawback is that the build can behave
+ differently if it's run by people with
+ different &PATH; values in their environment--for example,
+ if both the <literal>/bin</literal> and
+ <literal>/usr/local/bin</literal> directories
+ have different &cc; commands,
+ then which one will be used to compile programs
+ will depend on which directory is listed
+ first in the user's &PATH; variable.
+
+ </para>
+
+ </section>
+
+ <section>
+ <title>Adding to <varname>PATH</varname> Values in the Execution Environment</title>
+
+ <para>
+
+ One of the most common requirements
+ for manipulating a variable in the execution environment
+ is to add one or more custom directories to a search
+ like the <envar>$PATH</envar> variable on Linux or POSIX systems,
+ or the <envar>%PATH%</envar> variable on Windows,
+ so that a locally-installed compiler or other utility
+ can be found when &SCons; tries to execute it to update a target.
+ &SCons; provides &PrependENVPath; and &AppendENVPath; functions
+ to make adding things to execution variables convenient.
+ You call these functions by specifying the variable
+ to which you want the value added,
+ and then value itself.
+ So to add some <filename>/usr/local</filename> directories
+ to the <envar>$PATH</envar> and <envar>$LIB</envar> variables,
+ you might:
+
+ </para>
+
+ <programlisting>
+ env = Environment(ENV = os.environ)
+ env.PrependENVPath('PATH', '/usr/local/bin')
+ env.AppendENVPath('LIB', '/usr/local/lib')
+ </programlisting>
+
+ <para>
+
+ Note that the added values are strings,
+ and if you want to add multiple directories to
+ a variable like <envar>$PATH</envar>,
+ you must include the path separate character
+ (<literal>:</literal> on Linux or POSIX,
+ <literal>;</literal> on Windows)
+ in the string.
+
+ </para>
+
+ </section>
+
+ </section>
<para>
Suppose you want to arrange to make a copy of a file,
- and the &Install; builder isn't appropriate
- because it may make a hard link on POSIX systems.
+ and don't have a suitable pre-existing builder.
+ <footnote>
+ <para>
+ Unfortunately, in the early days of SCons design,
+ we used the name &Copy; for the function that
+ returns a copy of the environment,
+ otherwise that would be the logical choice for
+ a Builder that copies a file or directory tree
+ to a target location.
+ </para>
+ </footnote>
One way would be to use the &Copy; action factory
in conjunction with the &Command; builder:
<para>
- (Note, however, that you typically don't need to
+ Note, however, that you typically don't need to
call the &Delete; factory explicitly in this way;
by default, &SCons; deletes its target(s)
for you before executing any action.
</para>
+ <para>
+
+ One word of caution about using the &Delete; factory:
+ it has the same variable expansions available
+ as any other factory, including the &cv-SOURCE; variable.
+ Specifying <literal>Delete("$SOURCE")</literal>
+ is not something you usually want to do!
+
+ </para>
+
</section>
<section>
<para>
Suppose you want to arrange to make a copy of a file,
- and the &Install; builder isn't appropriate
- because it may make a hard link on POSIX systems.
+ and don't have a suitable pre-existing builder.
+ <footnote>
+ <para>
+ Unfortunately, in the early days of SCons design,
+ we used the name &Copy; for the function that
+ returns a copy of the environment,
+ otherwise that would be the logical choice for
+ a Builder that copies a file or directory tree
+ to a target location.
+ </para>
+ </footnote>
One way would be to use the &Copy; action factory
in conjunction with the &Command; builder:
<para>
- (Note, however, that you typically don't need to
+ Note, however, that you typically don't need to
call the &Delete; factory explicitly in this way;
by default, &SCons; deletes its target(s)
for you before executing any action.
</para>
+ <para>
+
+ One word of caution about using the &Delete; factory:
+ it has the same variable expansions available
+ as any other factory, including the &cv-SOURCE; variable.
+ Specifying <literal>Delete("$SOURCE")</literal>
+ is not something you usually want to do!
+
+ </para>
+
</section>
<section>
+++ /dev/null
-<!--
-
- __COPYRIGHT__
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
- KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
--->
-
- <para>
-
- It's often very useful to be able to give
- users some help that describes the
- specific targets, build options, etc.,
- that can be used for your build.
- &SCons; provides the &Help; function
- to allow you to specify this help text:
-
- </para>
-
- <scons_example name="ex1">
- <file name="SConstruct" printme="1">
- Help("""
- Type: 'scons program' to build the production program,
- 'scons debug' to build the debug version.
- """)
- </file>
- </scons_example>
-
- <para>
-
- (Note the above use of the Python triple-quote syntax,
- which comes in very handy for
- specifying multi-line strings like help text.)
-
- </para>
-
- <para>
-
- When the &SConstruct; or &SConscript; files
- contain such a call to the &Help; function,
- the specified help text will be displayed in response to
- the &SCons; <literal>-h</literal> option:
-
- </para>
-
- <scons_output example="ex1">
- <scons_output_command>scons -h</scons_output_command>
- </scons_output>
-
- <para>
-
- The &SConscript; files may contain
- multiple calls to the &Help; function,
- in which case the specified text(s)
- will be concatenated when displayed.
- This allows you to split up the
- help text across multiple &SConscript; files.
- In this situation, the order in
- which the &SConscript; files are called
- will determine the order in which the &Help; functions are called,
- which will determine the order in which
- the various bits of text will get concatenated.
-
- </para>
-
- <para>
-
- Another use would be to make the help text conditional
- on some variable.
- For example, suppose you only want to display
- a line about building a Windows-only
- version of a program when actually
- run on Windows.
- The following &SConstruct; file:
-
- </para>
-
- <scons_example name="ex2">
- <file name="SConstruct" printme="1">
- env = Environment()
-
- Help("\nType: 'scons program' to build the production program.\n")
-
- if env['PLATFORM'] == 'win32':
- Help("\nType: 'scons windebug' to build the Windows debug version.\n")
- </file>
- </scons_example>
-
- <para>
-
- Will display the complete help text on Windows:
-
- </para>
-
- <scons_output example="ex2" os="win32">
- <scons_output_command>scons -h</scons_output_command>
- </scons_output>
-
- <para>
-
- But only show the relevant option on a Linux or UNIX system:
-
- </para>
-
- <scons_output example="ex2" os="posix">
- <scons_output_command>scons -h</scons_output_command>
- </scons_output>
-
- <para>
-
- If there is no &Help; text in the &SConstruct; or
- &SConscript; files,
- &SCons; will revert to displaying its
- standard list that describes the &SCons; command-line
- options.
- This list is also always displayed whenever
- the <literal>-H</literal> option is used.
-
- </para>
+++ /dev/null
-<!--
-
- __COPYRIGHT__
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
- KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
--->
-
- <para>
-
- It's often very useful to be able to give
- users some help that describes the
- specific targets, build options, etc.,
- that can be used for your build.
- &SCons; provides the &Help; function
- to allow you to specify this help text:
-
- </para>
-
- <programlisting>
- Help("""
- Type: 'scons program' to build the production program,
- 'scons debug' to build the debug version.
- """)
- </programlisting>
-
- <para>
-
- (Note the above use of the Python triple-quote syntax,
- which comes in very handy for
- specifying multi-line strings like help text.)
-
- </para>
-
- <para>
-
- When the &SConstruct; or &SConscript; files
- contain such a call to the &Help; function,
- the specified help text will be displayed in response to
- the &SCons; <literal>-h</literal> option:
-
- </para>
-
- <screen>
- % <userinput>scons -h</userinput>
- scons: Reading SConscript files ...
- scons: done reading SConscript files.
-
- Type: 'scons program' to build the production program,
- 'scons debug' to build the debug version.
-
- Use scons -H for help about command-line options.
- </screen>
-
- <para>
-
- The &SConscript; files may contain
- multiple calls to the &Help; function,
- in which case the specified text(s)
- will be concatenated when displayed.
- This allows you to split up the
- help text across multiple &SConscript; files.
- In this situation, the order in
- which the &SConscript; files are called
- will determine the order in which the &Help; functions are called,
- which will determine the order in which
- the various bits of text will get concatenated.
-
- </para>
-
- <para>
-
- Another use would be to make the help text conditional
- on some variable.
- For example, suppose you only want to display
- a line about building a Windows-only
- version of a program when actually
- run on Windows.
- The following &SConstruct; file:
-
- </para>
-
- <programlisting>
- env = Environment()
-
- Help("\nType: 'scons program' to build the production program.\n")
-
- if env['PLATFORM'] == 'win32':
- Help("\nType: 'scons windebug' to build the Windows debug version.\n")
- </programlisting>
-
- <para>
-
- Will display the complete help text on Windows:
-
- </para>
-
- <screen>
- C:\><userinput>scons -h</userinput>
- scons: Reading SConscript files ...
- scons: done reading SConscript files.
-
- Type: 'scons program' to build the production program.
-
- Type: 'scons windebug' to build the Windows debug version.
-
- Use scons -H for help about command-line options.
- </screen>
-
- <para>
-
- But only show the relevant option on a Linux or UNIX system:
-
- </para>
-
- <screen>
- % <userinput>scons -h</userinput>
- scons: Reading SConscript files ...
- scons: done reading SConscript files.
-
- Type: 'scons program' to build the production program.
-
- Use scons -H for help about command-line options.
- </screen>
-
- <para>
-
- If there is no &Help; text in the &SConstruct; or
- &SConscript; files,
- &SCons; will revert to displaying its
- standard list that describes the &SCons; command-line
- options.
- This list is also always displayed whenever
- the <literal>-H</literal> option is used.
-
- </para>
</section>
<section>
- <title>Making a list of files with Glob()</title>
+ <title>Making a list of files with &Glob;</title>
<para>
- You can also use the Glob() function to find all files matching a
- certain template, using standard the shell pattern matching
- characters *, ?, and [abc] to match any of a, b, or c. [!abc] is
- also supported, to match any character <emphasis>except</emphasis>
- a, b, or c. This makes many multi-source-file builds quite easy:
+ You can also use the &Glob; function to find all files matching a
+ certain template, using the standard shell pattern matching
+ characters <literal>*</literal>, <literal>?</literal>
+ and <literal>[abc]</literal> to match any of
+ <literal>a</literal>, <literal>b</literal> or <literal>c</literal>.
+ <literal>[!abc]</literal> is also supported,
+ to match any character <emphasis>except</emphasis>
+ <literal>a</literal>, <literal>b</literal> or <literal>c</literal>.
+ This makes many multi-source-file builds quite easy:
</para>
<para>
- The SCons man page has more details on using Glob() with Variant
- dirs and Repositories and returning strings rather than Nodes.
+ The SCons man page has more details on using &Glob; with Variant
+ directories and Repositories, and returning strings rather than Nodes.
</para>
</para>
<programlisting>
- list = Split('main.c file1.c file2.c')
- Program('program', list)
+ src_files = Split('main.c file1.c file2.c')
+ Program('program', src_files)
</programlisting>
<para>
</para>
<programlisting>
- list = Split("""main.c
- file1.c
- file2.c""")
- Program('program', list)
+ src_files = Split("""main.c
+ file1.c
+ file2.c""")
+ Program('program', src_files)
</programlisting>
<para>
</para>
<programlisting>
- list = Split('main.c file1.c file2.c')
- Program(target = 'program', source = list)
+ src_files = Split('main.c file1.c file2.c')
+ Program(target = 'program', source = src_files)
</programlisting>
<para>
</para>
<programlisting>
- list = Split('main.c file1.c file2.c')
- Program(source = list, target = 'program')
+ src_files = Split('main.c file1.c file2.c')
+ Program(source = src_files, target = 'program')
</programlisting>
<para>
</section>
<section>
- <title>Making a list of files with Glob()</title>
+ <title>Making a list of files with &Glob;</title>
<para>
- You can also use the Glob() function to find all files matching a
- certain template, using standard the shell pattern matching
- characters *, ?, and [abc] to match any of a, b, or c. [!abc] is
- also supported, to match any character <emphasis>except</emphasis>
- a, b, or c. This makes many multi-source-file builds quite easy:
+ You can also use the &Glob; function to find all files matching a
+ certain template, using the standard shell pattern matching
+ characters <literal>*</literal>, <literal>?</literal>
+ and <literal>[abc]</literal> to match any of
+ <literal>a</literal>, <literal>b</literal> or <literal>c</literal>.
+ <literal>[!abc]</literal> is also supported,
+ to match any character <emphasis>except</emphasis>
+ <literal>a</literal>, <literal>b</literal> or <literal>c</literal>.
+ This makes many multi-source-file builds quite easy:
</para>
<para>
- The SCons man page has more details on using Glob() with Variant
- dirs and Repositories and returning strings rather than Nodes.
+ The SCons man page has more details on using &Glob; with Variant
+ directories and Repositories, and returning strings rather than Nodes.
</para>
</para>
<programlisting>
- list = Split('main.c file1.c file2.c')
- Program('program', list)
+ src_files = Split('main.c file1.c file2.c')
+ Program('program', src_files)
</programlisting>
<para>
</para>
<programlisting>
- list = Split("""main.c
- file1.c
- file2.c""")
- Program('program', list)
+ src_files = Split("""main.c
+ file1.c
+ file2.c""")
+ Program('program', src_files)
</programlisting>
<para>
</para>
<programlisting>
- list = Split('main.c file1.c file2.c')
- Program(target = 'program', source = list)
+ src_files = Split('main.c file1.c file2.c')
+ Program(target = 'program', source = src_files)
</programlisting>
<para>
</para>
<programlisting>
- list = Split('main.c file1.c file2.c')
- Program(source = list, target = 'program')
+ src_files = Split('main.c file1.c file2.c')
+ Program(source = src_files, target = 'program')
</programlisting>
<para>
<!ENTITY command-line SYSTEM "command-line.xml">
<!ENTITY copyright SYSTEM "copyright.xml">
<!ENTITY depends SYSTEM "depends.xml">
- <!ENTITY ENV_file SYSTEM "ENV.xml">
<!ENTITY environments SYSTEM "environments.xml">
<!ENTITY errors SYSTEM "errors.xml">
<!ENTITY example SYSTEM "example.xml">
<!ENTITY factories SYSTEM "factories.xml">
<!ENTITY file-removal SYSTEM "file-removal.xml">
- <!ENTITY help SYSTEM "help.xml">
<!ENTITY hierarchy SYSTEM "hierarchy.xml">
<!ENTITY java SYSTEM "java.xml">
<!ENTITY install SYSTEM "install.xml">
<!ENTITY less-simple SYSTEM "less-simple.xml">
<!ENTITY libraries SYSTEM "libraries.xml">
<!ENTITY make SYSTEM "make.xml">
+ <!ENTITY mergeflags SYSTEM "mergeflags.xml">
+ <!ENTITY misc SYSTEM "misc.xml">
<!ENTITY nodes SYSTEM "nodes.xml">
+ <!ENTITY output SYSTEM "output.xml">
<!ENTITY parseconfig SYSTEM "parseconfig.xml">
+ <!ENTITY parseflags SYSTEM "parseflags.xml">
<!ENTITY preface SYSTEM "preface.xml">
<!ENTITY python SYSTEM "python.xml">
<!ENTITY repositories SYSTEM "repositories.xml">
<!ENTITY tasks SYSTEM "tasks.xml">
<!ENTITY tools SYSTEM "tools.xml">
<!ENTITY troubleshoot SYSTEM "troubleshoot.xml">
- <!ENTITY variables SYSTEM "variables.xml">
+ <!ENTITY variables-xml SYSTEM "variables.xml">
<!ENTITY variants SYSTEM "variants.xml">
<!ENTITY builders-gen SYSTEM "builders.gen">
<!--
- XXX AllowSubstExceptions()
- XXX EnsurePythonVersion()
- XXX EnsureSConsVersion()
- XXX Exit()
XXX FindFile()
XXX FindPathDirs()
- XXX Flatten()
XXX GetBuildPath()
XXX GetLaunchDir()
- XXX ParseConfig()
- XXX MergeFlags()
- XXX ParseFlags()
-
XXX ParseDepends()
XXX Platform()
XXX SConsignFile()
- XXX SideEffect()
XXX Tools()
- XXX GetOption('clean')
- XXX SetOption('clean')
-
XXX GetOption('duplicate')
XXX SetOption('duplicate')
XXX - - duplicate=
- XXX GetOption('help')
- XXX SetOption('help')
-
- XXX GetOption('num_jobs')
- XXX SetOption('num_jobs')
-
- XXX Options.UnknownOption()
-
- XXX GetBuildFailures()
-
- XXX Requires()
-
XXX CheckTypeSize()
- XXX Progress()
-
XXX - - diskcheck=
XXX - - warn=
- XXX ARGLIST
- XXX ARGUMENTS
- XXX BUILD_TARGETS
- XXX COMMAND_LINE_TARGETS
- XXX DEFAULT_TARGETS
-
-->
<book>
<edition>Revision &buildrevision; (&builddate;)</edition>
- <pubdate>2004, 2005, 2006, 2007</pubdate>
+ <pubdate>2004, 2005, 2006, 2007, 2008</pubdate>
<copyright>
- <year>2004, 2005, 2006, 2007</year>
+ <year>2004, 2005, 2006, 2007, 2008</year>
<holder>Steven Knight</holder>
</copyright>
</chapter>
<chapter id="chap-environments">
- <title>Construction Environments</title>
+ <title>Environments</title>
&environments;
</chapter>
- <!--
-
+ <!-- These next three sections should be combined into one chapter -->
+ <chapter id="chap-mergeflags">
+ <title>Merging Options into the Environment: the &MergeFlags; Function</title>
+ &mergeflags;
+ </chapter>
+ <chapter id="chap-parseflags">
+ <title>Separating Compile Arguments into their Variables: the &ParseFlags; Function</title>
+ &parseflags;
+ </chapter>
<chapter id="chap-parseconfig">
<title>Finding Installed Library Information: the &ParseConfig; Function</title>
&parseconfig;
</chapter>
- -->
-
- <chapter id="chap-ENV">
- <title>Controlling the External Environment Used to Execute Build Commands</title>
- &ENV_file;
+ <chapter id="chap-output">
+ <title>Controlling Build Output</title>
+ &output;
</chapter>
<chapter id="chap-command-line">
&command-line;
</chapter>
- <chapter id="chap-help">
- <title>Providing Build Help: the &Help; Function</title>
- &help;
- </chapter>
-
<chapter id="chap-install">
<title>Installing Files in Other Directories: the &Install; Builder</title>
&install;
</chapter>
<chapter id="chap-file-removal">
- <title>Preventing Removal of Targets</title>
+ <title>Controlling Removal of Targets</title>
&file-removal;
</chapter>
-->
+ <chapter id="chap-misc">
+ <title>Miscellaneous Functionality</title>
+ &misc;
+ </chapter>
+
<chapter id="chap-troubleshooting">
<title>Troubleshooting</title>
&troubleshoot;
<appendix id="app-variables">
<title>Construction Variables</title>
- &variables;
+ &variables-xml;
</appendix>
<appendix id="app-builders">
<!ENTITY command-line SYSTEM "command-line.xml">
<!ENTITY copyright SYSTEM "copyright.xml">
<!ENTITY depends SYSTEM "depends.xml">
- <!ENTITY ENV_file SYSTEM "ENV.xml">
<!ENTITY environments SYSTEM "environments.xml">
<!ENTITY errors SYSTEM "errors.xml">
<!ENTITY example SYSTEM "example.xml">
<!ENTITY factories SYSTEM "factories.xml">
<!ENTITY file-removal SYSTEM "file-removal.xml">
- <!ENTITY help SYSTEM "help.xml">
<!ENTITY hierarchy SYSTEM "hierarchy.xml">
<!ENTITY java SYSTEM "java.xml">
<!ENTITY install SYSTEM "install.xml">
<!ENTITY less-simple SYSTEM "less-simple.xml">
<!ENTITY libraries SYSTEM "libraries.xml">
<!ENTITY make SYSTEM "make.xml">
+ <!ENTITY mergeflags SYSTEM "mergeflags.xml">
+ <!ENTITY misc SYSTEM "misc.xml">
<!ENTITY nodes SYSTEM "nodes.xml">
+ <!ENTITY output SYSTEM "output.xml">
<!ENTITY parseconfig SYSTEM "parseconfig.xml">
+ <!ENTITY parseflags SYSTEM "parseflags.xml">
<!ENTITY preface SYSTEM "preface.xml">
<!ENTITY python SYSTEM "python.xml">
<!ENTITY repositories SYSTEM "repositories.xml">
<!ENTITY tasks SYSTEM "tasks.xml">
<!ENTITY tools SYSTEM "tools.xml">
<!ENTITY troubleshoot SYSTEM "troubleshoot.xml">
- <!ENTITY variables SYSTEM "variables.xml">
+ <!ENTITY variables-xml SYSTEM "variables.xml">
<!ENTITY variants SYSTEM "variants.xml">
<!ENTITY builders-gen SYSTEM "builders.gen">
<!--
- XXX AllowSubstExceptions()
- XXX EnsurePythonVersion()
- XXX EnsureSConsVersion()
- XXX Exit()
XXX FindFile()
XXX FindPathDirs()
- XXX Flatten()
XXX GetBuildPath()
XXX GetLaunchDir()
- XXX ParseConfig()
- XXX MergeFlags()
- XXX ParseFlags()
-
XXX ParseDepends()
XXX Platform()
XXX SConsignFile()
XXX SideEffect()
XXX Tools()
- XXX GetOption('clean')
- XXX SetOption('clean')
-
XXX GetOption('duplicate')
XXX SetOption('duplicate')
XXX - - duplicate=
- XXX GetOption('help')
- XXX SetOption('help')
-
- XXX GetOption('num_jobs')
- XXX SetOption('num_jobs')
-
- XXX Options.UnknownOption()
-
- XXX GetBuildFailures()
-
- XXX Requires()
-
XXX CheckTypeSize()
- XXX Progress()
-
XXX - - diskcheck=
XXX - - warn=
- XXX ARGLIST
- XXX ARGUMENTS
- XXX BUILD_TARGETS
- XXX COMMAND_LINE_TARGETS
- XXX DEFAULT_TARGETS
-
-->
<book>
<edition>Revision &buildrevision; (&builddate;)</edition>
- <pubdate>2004, 2005, 2006, 2007</pubdate>
+ <pubdate>2004, 2005, 2006, 2007, 2008</pubdate>
<copyright>
- <year>2004, 2005, 2006, 2007</year>
+ <year>2004, 2005, 2006, 2007, 2008</year>
<holder>Steven Knight</holder>
</copyright>
</chapter>
<chapter id="chap-environments">
- <title>Construction Environments</title>
+ <title>Environments</title>
&environments;
</chapter>
- <!--
-
+ <!-- These next three sections should be combined into one chapter -->
+ <chapter id="chap-mergeflags">
+ <title>Merging Options into the Environment: the &MergeFlags; Function</title>
+ &mergeflags;
+ </chapter>
+ <chapter id="chap-parseflags">
+ <title>Separating Compile Arguments into their Variables: the &ParseFlags; Function</title>
+ &parseflags;
+ </chapter>
<chapter id="chap-parseconfig">
<title>Finding Installed Library Information: the &ParseConfig; Function</title>
&parseconfig;
</chapter>
- -->
-
- <chapter id="chap-ENV">
- <title>Controlling the External Environment Used to Execute Build Commands</title>
- &ENV_file;
+ <chapter id="chap-output">
+ <title>Controlling Build Output</title>
+ &output;
</chapter>
<chapter id="chap-command-line">
&command-line;
</chapter>
- <chapter id="chap-help">
- <title>Providing Build Help: the &Help; Function</title>
- &help;
- </chapter>
-
<chapter id="chap-install">
<title>Installing Files in Other Directories: the &Install; Builder</title>
&install;
</chapter>
<chapter id="chap-file-removal">
- <title>Preventing Removal of Targets</title>
+ <title>Controlling Removal of Targets</title>
&file-removal;
</chapter>
-->
+ <chapter id="chap-misc">
+ <title>Miscellaneous Functionality</title>
+ &misc;
+ </chapter>
+
<chapter id="chap-troubleshooting">
<title>Troubleshooting</title>
&troubleshoot;
<appendix id="app-variables">
<title>Construction Variables</title>
- &variables;
+ &variables-xml;
</appendix>
<appendix id="app-builders">
--- /dev/null
+<!--
+
+ __COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+ <para>
+
+ &SCons; construction environments have a &MergeFlags; method
+ that merges a dictionary of values into the construction environment.
+ &MergeFlags; treats each value in the dictionary
+ as a list of options such as one might pass to a command
+ (such as a compiler or linker).
+ &MergeFlags; will not duplicate an option
+ if it already exists in the construction environment variable.
+
+ </para>
+
+ <para>
+
+ &MergeFlags; tries to be intelligent about merging options.
+ When merging options to any variable
+ whose name ends in <varname>PATH</varname>,
+ &MergeFlags; keeps the leftmost occurrence of the option,
+ because in typical lists of directory paths,
+ the first occurrence "wins."
+ When merging options to any other variable name,
+ &MergeFlags; keeps the rightmost occurrence of the option,
+ because in a list of typical command-line options,
+ the last occurrence "wins."
+
+ </para>
+
+ <scons_example name="MergeFlags1">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ env.Append(CCFLAGS = '-option -O3 -O1')
+ flags = { 'CCFLAGS' : '-whatever -O3' }
+ env.MergeFlags(flags)
+ print env['CCFLAGS']
+ </file>
+ </scons_example>
+
+ <scons_output example="MergeFlags1">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ Note that the default value for &cv-link-CCFLAGS;
+ <!--
+ [TODO: for when we make CLVar public]
+ is a <varname>CLVar</varname>,
+ -->
+ is an internal &SCons; object
+ which automatically converts
+ the options we specified as a string into a list.
+
+ </para>
+
+ <scons_example name="MergeFlags2">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include'])
+ flags = { 'CPPPATH' : ['/usr/opt/include', '/usr/local/include'] }
+ env.MergeFlags(flags)
+ print env['CPPPATH']
+ </file>
+ </scons_example>
+
+ <scons_output example="MergeFlags2">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ Note that the default value for &cv-link-CPPPATH;
+ <!--
+ [TODO: for when we make CLVar public]
+ is a Python list, not a <varname>CLVar</varname>,
+ -->
+ is a normal Python list,
+ so we must specify its values as a list
+ in the dictionary we pass to the &MergeFlags; function.
+
+ </para>
+
+ <para>
+
+ If &MergeFlags; is passed anything other than a dictionary,
+ it calls the &ParseFlags; method to convert it into a dictionary.
+
+ </para>
+
+ <scons_example name="MergeFlags3">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ env.Append(CCFLAGS = '-option -O3 -O1')
+ env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include'])
+ env.MergeFlags('-whatever -I/usr/opt/include -O3 -I/usr/local/include')
+ print env['CCFLAGS']
+ print env['CPPPATH']
+ </file>
+ </scons_example>
+
+ <scons_output example="MergeFlags3">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ In the combined example above,
+ &ParseFlags; has sorted the options into their corresponding variables
+ and returned a dictionary for &MergeFlags; to apply
+ to the construction variables
+ in the specified construction environment.
+
+ </para>
--- /dev/null
+<!--
+
+ __COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+ <para>
+
+ &SCons; construction environments have a &MergeFlags; method
+ that merges a dictionary of values into the construction environment.
+ &MergeFlags; treats each value in the dictionary
+ as a list of options such as one might pass to a command
+ (such as a compiler or linker).
+ &MergeFlags; will not duplicate an option
+ if it already exists in the construction environment variable.
+
+ </para>
+
+ <para>
+
+ &MergeFlags; tries to be intelligent about merging options.
+ When merging options to any variable
+ whose name ends in <varname>PATH</varname>,
+ &MergeFlags; keeps the leftmost occurrence of the option,
+ because in typical lists of directory paths,
+ the first occurrence "wins."
+ When merging options to any other variable name,
+ &MergeFlags; keeps the rightmost occurrence of the option,
+ because in a list of typical command-line options,
+ the last occurrence "wins."
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ env.Append(CCFLAGS = '-option -O3 -O1')
+ flags = { 'CCFLAGS' : '-whatever -O3' }
+ env.MergeFlags(flags)
+ print env['CCFLAGS']
+ </programlisting>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ ['-option', '-O1', '-whatever', '-O3']
+ scons: `.' is up to date.
+ </screen>
+
+ <para>
+
+ Note that the default value for &cv-link-CCFLAGS;
+ <!--
+ [TODO: for when we make CLVar public]
+ is a <varname>CLVar</varname>,
+ -->
+ is an internal &SCons; object
+ which automatically converts
+ the options we specified as a string into a list.
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include'])
+ flags = { 'CPPPATH' : ['/usr/opt/include', '/usr/local/include'] }
+ env.MergeFlags(flags)
+ print env['CPPPATH']
+ </programlisting>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ ['/include', '/usr/local/include', '/usr/include', '/usr/opt/include']
+ scons: `.' is up to date.
+ </screen>
+
+ <para>
+
+ Note that the default value for &cv-link-CPPPATH;
+ <!--
+ [TODO: for when we make CLVar public]
+ is a Python list, not a <varname>CLVar</varname>,
+ -->
+ is a normal Python list,
+ so we must specify its values as a list
+ in the dictionary we pass to the &MergeFlags; function.
+
+ </para>
+
+ <para>
+
+ If &MergeFlags; is passed anything other than a dictionary,
+ it calls the &ParseFlags; method to convert it into a dictionary.
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ env.Append(CCFLAGS = '-option -O3 -O1')
+ env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include'])
+ env.MergeFlags('-whatever -I/usr/opt/include -O3 -I/usr/local/include')
+ print env['CCFLAGS']
+ print env['CPPPATH']
+ </programlisting>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ ['-option', '-O1', '-whatever', '-O3']
+ ['/include', '/usr/local/include', '/usr/include', '/usr/opt/include']
+ scons: `.' is up to date.
+ </screen>
+
+ <para>
+
+ In the combined example above,
+ &ParseFlags; has sorted the options into their corresponding variables
+ and returned a dictionary for &MergeFlags; to apply
+ to the construction variables
+ in the specified construction environment.
+
+ </para>
--- /dev/null
+<!--
+
+ __COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+ <para>
+
+ &SCons; supports a lot of additional functionality
+ that doesn't readily fit into the other chapters.
+
+ </para>
+
+ <section>
+ <title>Verifying the Python Version: the &EnsurePythonVersion; Function</title>
+
+ <para>
+
+ Although the &SCons; code itself will run
+ on any Python version 1.5.2 or later,
+ you are perfectly free to make use of
+ Python syntax and modules from more modern versions
+ (for example, Python 2.4 or 2.5)
+ when writing your &SConscript; files
+ or your own local modules.
+ If you do this, it's usually helpful to
+ configure &SCons; to exit gracefully with an error message
+ if it's being run with a version of Python
+ that simply won't work with your code.
+ This is especially true if you're going to use &SCons;
+ to build source code that you plan to distribute publicly,
+ where you can't be sure of the Python version
+ that an anonymous remote user might use
+ to try to build your software.
+
+ </para>
+
+ <para>
+
+ &SCons; provides an &EnsurePythonVersion; function for this.
+ You simply pass it the major and minor versions
+ numbers of the version of Python you require:
+
+ </para>
+
+ <!--
+
+ TODO: Figure out how to generate the error message
+ regardless of executing Python version by faking out
+ the infrastructure in some way.
+
+ <scons_example name="EnsurePythonVersion">
+ <file name="SConstruct" printme="1">
+ EnsurePythonVersion(2, 5)
+ </file>
+ </scons_example>
+
+ -->
+
+ <sconstruct>
+ EnsurePythonVersion(2, 5)
+ </sconstruct>
+
+ <para>
+
+ And then &SCons will exit with the following error
+ message when a user runs it with an unsupported
+ earlier version of Python:
+
+ </para>
+
+ <!--
+
+ TODO: Figure out how to generate the error message
+ regardless of executing Python version by faking out
+ the infrastructure in some way.
+
+ <scons_output example="EnsurePythonVersion">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ Python 2.5 or greater required, but you have Python 2.3.6
+ </screen>
+
+ </section>
+
+ <section>
+ <title>Verifying the SCons Version: the &EnsureSConsVersion; Function</title>
+
+ <para>
+
+ You may, of course, write your &SConscript; files
+ to use features that were only added in
+ recent versions of &SCons;.
+ When you publicly distribute software that is built using &SCons;,
+ it's helpful to have &SCons;
+ verify the version being used and
+ exit gracefully with an error message
+ if the user's version of &SCons; won't work
+ with your &SConscript; files.
+ &SCons; provides an &EnsureSConsVersion; function
+ that verifies the version of &SCons;
+ in the same
+ the &EnsurePythonVersion; function
+ verifies the version of Python,
+ by passing in the major and minor versions
+ numbers of the version of SCons you require:
+
+ </para>
+
+ <!--
+
+ TODO: Figure out how to generate the error message
+ regardless of executing SCons version by faking out
+ the infrastructure in some way.
+
+ <scons_example name="EnsureSConsVersion">
+ <file name="SConstruct" printme="1">
+ EnsureSConsVersion(1, 0)
+ </file>
+ </scons_example>
+
+ -->
+
+ <sconstruct>
+ EnsureSConsVersion(1, 0)
+ </sconstruct>
+
+ <para>
+
+ And then &SCons will exit with the following error
+ message when a user runs it with an unsupported
+ earlier version of &SCons;:
+
+ </para>
+
+ <!--
+
+ TODO: Figure out how to generate the error message
+ regardless of executing SCons version by faking out
+ the infrastructure in some way.
+
+ <scons_output example="EnsureSConsVersion">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ SCons 1.0 or greater required, but you have SCons 0.98.5
+ </screen>
+
+ </section>
+
+ <section>
+ <title>Explicitly Terminating &SCons; While Reading &SConscript; Files: the &Exit; Function</title>
+
+ <para>
+
+ &SCons; supports an &Exit; function
+ which can be used to terminate &SCons;
+ while reading the &SConscript; files,
+ usually because you've detected a condition
+ under which it doesn't make sense to proceed:
+
+ </para>
+
+ <scons_example name="Exit">
+ <file name="SConstruct" printme="1">
+ if ARGUMENTS.get('FUTURE'):
+ print "The FUTURE option is not supported yet!"
+ Exit(2)
+ env = Environment()
+ env.Program('hello.c')
+ </file>
+ <file name="hello.c">
+ hello.c
+ </file>
+ </scons_example>
+
+ <scons_output example="Exit">
+ <scons_output_command>scons -Q FUTURE=1</scons_output_command>
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ The &Exit; function takes as an argument
+ the (numeric) exit status that you want &SCons; to exit with.
+ If you don't specify a value,
+ the default is to exit with <literal>0</literal>,
+ which indicates successful execution.
+
+ </para>
+
+ <para>
+
+ Note that the &Exit; function
+ is equivalent to calling the Python
+ <function>sys.exit</function> function
+ (which the it actually calls),
+ but because &Exit; is a &SCons; function,
+ you don't have to import the Python
+ <literal>sys</literal> module to use it.
+
+ </para>
+
+ </section>
+
+ <section>
+ <title>Handling Nested Lists: the &Flatten; Function</title>
+
+ <para>
+
+ &SCons; supports a &Flatten; function
+ which takes an input Python sequence
+ (list or tuple)
+ and returns a flattened list
+ containing just the individual elements of
+ the sequence.
+ This can be handy when trying to examine
+ a list composed of the lists
+ returned by calls to various Builders.
+ For example, you might collect
+ object files built in different ways
+ into one call to the &Program; Builder
+ by just enclosing them in a list, as follows:
+
+ </para>
+
+ <scons_example name="Flatten1">
+ <file name="SConstruct" printme="1">
+ objects = [
+ Object('prog1.c'),
+ Object('prog2.c', CCFLAGS='-DFOO'),
+ ]
+ Program(objects)
+ </file>
+ <file name="prog1.c">
+ prog1.c
+ </file>
+ <file name="prog2.c">
+ prog2.c
+ </file>
+ </scons_example>
+
+ <para>
+
+ Because the Builder calls in &SCons;
+ flatten their input lists,
+ this works just fine to build the program:
+
+ </para>
+
+ <scons_output example="Flatten1">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ But if you were debugging your build
+ and wanted to print the absolute path
+ of each object file in the
+ <varname>objects</varname> list,
+ you might try the following simple approach,
+ trying to print each Node's
+ <literal>abspath</literal>
+ attribute:
+
+ </para>
+
+ <scons_example name="Flatten2">
+ <file name="SConstruct" printme="1">
+ objects = [
+ Object('prog1.c'),
+ Object('prog2.c', CCFLAGS='-DFOO'),
+ ]
+ Program(objects)
+
+ for object_file in objects:
+ print object_file.abspath
+ </file>
+ <file name="prog1.c">
+ prog1.c
+ </file>
+ <file name="prog2.c">
+ prog2.c
+ </file>
+ </scons_example>
+
+ <para>
+
+ This does not work as expected
+ because each call to <function>str</function>
+ is operating an embedded list returned by
+ each &Object; call,
+ not on the underlying Nodes within those lists:
+
+ </para>
+
+ <scons_output example="Flatten2">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ The solution is to use the &Flatten; function
+ so that you can pass each Node to
+ the <function>str</function> separately:
+
+ </para>
+
+ <scons_example name="Flatten3">
+ <file name="SConstruct" printme="1">
+ objects = [
+ Object('prog1.c'),
+ Object('prog2.c', CCFLAGS='-DFOO'),
+ ]
+ Program(objects)
+
+ for object_file in Flatten(objects):
+ print object_file.abspath
+ </file>
+ <file name="prog1.c">
+ prog1.c
+ </file>
+ <file name="prog2.c">
+ prog2.c
+ </file>
+ </scons_example>
+
+ <!--
+
+ TODO: can't use this now because it displays the temporary path name
+
+ <scons_output example="Flatten3">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ /home/me/project/prog1.o
+ /home/me/project/prog2.o
+ cc -o prog1.o -c prog1.c
+ cc -o prog2.o -c -DFOO prog2.c
+ cc -o prog1 prog1.o prog2.o
+ </screen>
+
+ </section>
--- /dev/null
+<!--
+
+ __COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+ <para>
+
+ &SCons; supports a lot of additional functionality
+ that doesn't readily fit into the other chapters.
+
+ </para>
+
+ <section>
+ <title>Verifying the Python Version: the &EnsurePythonVersion; Function</title>
+
+ <para>
+
+ Although the &SCons; code itself will run
+ on any Python version 1.5.2 or later,
+ you are perfectly free to make use of
+ Python syntax and modules from more modern versions
+ (for example, Python 2.4 or 2.5)
+ when writing your &SConscript; files
+ or your own local modules.
+ If you do this, it's usually helpful to
+ configure &SCons; to exit gracefully with an error message
+ if it's being run with a version of Python
+ that simply won't work with your code.
+ This is especially true if you're going to use &SCons;
+ to build source code that you plan to distribute publicly,
+ where you can't be sure of the Python version
+ that an anonymous remote user might use
+ to try to build your software.
+
+ </para>
+
+ <para>
+
+ &SCons; provides an &EnsurePythonVersion; function for this.
+ You simply pass it the major and minor versions
+ numbers of the version of Python you require:
+
+ </para>
+
+ <!--
+
+ TODO: Figure out how to generate the error message
+ regardless of executing Python version by faking out
+ the infrastructure in some way.
+
+ <scons_example name="EnsurePythonVersion">
+ <file name="SConstruct" printme="1">
+ EnsurePythonVersion(2, 5)
+ </file>
+ </scons_example>
+
+ -->
+
+ <programlisting>
+ EnsurePythonVersion(2, 5)
+ </programlisting>
+
+ <para>
+
+ And then &SCons; will exit with the following error
+ message when a user runs it with an unsupported
+ earlier version of Python:
+
+ </para>
+
+ <!--
+
+ TODO: Figure out how to generate the error message
+ regardless of executing Python version by faking out
+ the infrastructure in some way.
+
+ <scons_output example="EnsurePythonVersion">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ Python 2.5 or greater required, but you have Python 2.3.6
+ </screen>
+
+ </section>
+
+ <section>
+ <title>Verifying the SCons Version: the &EnsureSConsVersion; Function</title>
+
+ <para>
+
+ You may, of course, write your &SConscript; files
+ to use features that were only added in
+ recent versions of &SCons;.
+ When you publicly distribute software that is built using &SCons;,
+ it's helpful to have &SCons;
+ verify the version being used and
+ exit gracefully with an error message
+ if the user's version of &SCons; won't work
+ with your &SConscript; files.
+ &SCons; provides an &EnsureSConsVersion; function
+ that verifies the version of &SCons;
+ in the same
+ the &EnsurePythonVersion; function
+ verifies the version of Python,
+ by passing in the major and minor versions
+ numbers of the version of SCons you require:
+
+ </para>
+
+ <!--
+
+ TODO: Figure out how to generate the error message
+ regardless of executing SCons version by faking out
+ the infrastructure in some way.
+
+ <scons_example name="EnsureSConsVersion">
+ <file name="SConstruct" printme="1">
+ EnsureSConsVersion(1, 0)
+ </file>
+ </scons_example>
+
+ -->
+
+ <programlisting>
+ EnsureSConsVersion(1, 0)
+ </programlisting>
+
+ <para>
+
+ And then &SCons; will exit with the following error
+ message when a user runs it with an unsupported
+ earlier version of &SCons;:
+
+ </para>
+
+ <!--
+
+ TODO: Figure out how to generate the error message
+ regardless of executing SCons version by faking out
+ the infrastructure in some way.
+
+ <scons_output example="EnsureSConsVersion">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ SCons 1.0 or greater required, but you have SCons 0.98.5
+ </screen>
+
+ </section>
+
+ <section>
+ <title>Explicitly Terminating &SCons; While Reading &SConscript; Files: the &Exit; Function</title>
+
+ <para>
+
+ &SCons; supports an &Exit; function
+ which can be used to terminate &SCons;
+ while reading the &SConscript; files,
+ usually because you've detected a condition
+ under which it doesn't make sense to proceed:
+
+ </para>
+
+ <programlisting>
+ if ARGUMENTS.get('FUTURE'):
+ print "The FUTURE option is not supported yet!"
+ Exit(2)
+ env = Environment()
+ env.Program('hello.c')
+ </programlisting>
+
+ <screen>
+ % <userinput>scons -Q FUTURE=1</userinput>
+ The FUTURE option is not supported yet!
+ % <userinput>scons -Q</userinput>
+ cc -o hello.o -c hello.c
+ cc -o hello hello.o
+ </screen>
+
+ <para>
+
+ The &Exit; function takes as an argument
+ the (numeric) exit status that you want &SCons; to exit with.
+ If you don't specify a value,
+ the default is to exit with <literal>0</literal>,
+ which indicates successful execution.
+
+ </para>
+
+ <para>
+
+ Note that the &Exit; function
+ is equivalent to calling the Python
+ <function>sys.exit</function> function
+ (which the it actually calls),
+ but because &Exit; is a &SCons; function,
+ you don't have to import the Python
+ <literal>sys</literal> module to use it.
+
+ </para>
+
+ </section>
+
+ <section>
+ <title>Handling Nested Lists: the &Flatten; Function</title>
+
+ <para>
+
+ &SCons; supports a &Flatten; function
+ which takes an input Python sequence
+ (list or tuple)
+ and returns a flattened list
+ containing just the individual elements of
+ the sequence.
+ This can be handy when trying to examine
+ a list composed of the lists
+ returned by calls to various Builders.
+ For example, you might collect
+ object files built in different ways
+ into one call to the &Program; Builder
+ by just enclosing them in a list, as follows:
+
+ </para>
+
+ <programlisting>
+ objects = [
+ Object('prog1.c'),
+ Object('prog2.c', CCFLAGS='-DFOO'),
+ ]
+ Program(objects)
+ </programlisting>
+
+ <para>
+
+ Because the Builder calls in &SCons;
+ flatten their input lists,
+ this works just fine to build the program:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ cc -o prog1.o -c prog1.c
+ cc -o prog2.o -c -DFOO prog2.c
+ cc -o prog1 prog1.o prog2.o
+ </screen>
+
+ <para>
+
+ But if you were debugging your build
+ and wanted to print the absolute path
+ of each object file in the
+ <varname>objects</varname> list,
+ you might try the following simple approach,
+ trying to print each Node's
+ <literal>abspath</literal>
+ attribute:
+
+ </para>
+
+ <programlisting>
+ objects = [
+ Object('prog1.c'),
+ Object('prog2.c', CCFLAGS='-DFOO'),
+ ]
+ Program(objects)
+
+ for object_file in objects:
+ print object_file.abspath
+ </programlisting>
+
+ <para>
+
+ This does not work as expected
+ because each call to <function>str</function>
+ is operating an embedded list returned by
+ each &Object; call,
+ not on the underlying Nodes within those lists:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ AttributeError: NodeList instance has no attribute 'abspath':
+ File "/home/my/project/SConstruct", line 8:
+ print object_file.abspath
+ </screen>
+
+ <para>
+
+ The solution is to use the &Flatten; function
+ so that you can pass each Node to
+ the <function>str</function> separately:
+
+ </para>
+
+ <programlisting>
+ objects = [
+ Object('prog1.c'),
+ Object('prog2.c', CCFLAGS='-DFOO'),
+ ]
+ Program(objects)
+
+ for object_file in Flatten(objects):
+ print object_file.abspath
+ </programlisting>
+
+ <!--
+
+ TODO: can't use this now because it displays the temporary path name
+
+ <scons_output example="Flatten3">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ /home/me/project/prog1.o
+ /home/me/project/prog2.o
+ cc -o prog1.o -c prog1.c
+ cc -o prog2.o -c -DFOO prog2.c
+ cc -o prog1 prog1.o prog2.o
+ </screen>
+
+ </section>
--- /dev/null
+<!--
+
+ __COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+ <para>
+
+ A key aspect of creating a usable build configuration
+ is providing good output from the build
+ so its users can readily understand
+ what the build is doing
+ and get information about how to control the build.
+ &SCons; provides several ways of
+ controlling output from the build configuration
+ to help make the build
+ more useful and understandable.
+
+ </para>
+
+ <section>
+ <title>Providing Build Help: the &Help; Function</title>
+
+ <para>
+
+ It's often very useful to be able to give
+ users some help that describes the
+ specific targets, build options, etc.,
+ that can be used for your build.
+ &SCons; provides the &Help; function
+ to allow you to specify this help text:
+
+ </para>
+
+ <scons_example name="ex1">
+ <file name="SConstruct" printme="1">
+ Help("""
+ Type: 'scons program' to build the production program,
+ 'scons debug' to build the debug version.
+ """)
+ </file>
+ </scons_example>
+
+ <para>
+
+ (Note the above use of the Python triple-quote syntax,
+ which comes in very handy for
+ specifying multi-line strings like help text.)
+
+ </para>
+
+ <para>
+
+ When the &SConstruct; or &SConscript; files
+ contain such a call to the &Help; function,
+ the specified help text will be displayed in response to
+ the &SCons; <literal>-h</literal> option:
+
+ </para>
+
+ <scons_output example="ex1">
+ <scons_output_command>scons -h</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ The &SConscript; files may contain
+ multiple calls to the &Help; function,
+ in which case the specified text(s)
+ will be concatenated when displayed.
+ This allows you to split up the
+ help text across multiple &SConscript; files.
+ In this situation, the order in
+ which the &SConscript; files are called
+ will determine the order in which the &Help; functions are called,
+ which will determine the order in which
+ the various bits of text will get concatenated.
+
+ </para>
+
+ <para>
+
+ Another use would be to make the help text conditional
+ on some variable.
+ For example, suppose you only want to display
+ a line about building a Windows-only
+ version of a program when actually
+ run on Windows.
+ The following &SConstruct; file:
+
+ </para>
+
+ <scons_example name="ex2">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+
+ Help("\nType: 'scons program' to build the production program.\n")
+
+ if env['PLATFORM'] == 'win32':
+ Help("\nType: 'scons windebug' to build the Windows debug version.\n")
+ </file>
+ </scons_example>
+
+ <para>
+
+ Will display the complete help text on Windows:
+
+ </para>
+
+ <scons_output example="ex2" os="win32">
+ <scons_output_command>scons -h</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ But only show the relevant option on a Linux or UNIX system:
+
+ </para>
+
+ <scons_output example="ex2" os="posix">
+ <scons_output_command>scons -h</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ If there is no &Help; text in the &SConstruct; or
+ &SConscript; files,
+ &SCons; will revert to displaying its
+ standard list that describes the &SCons; command-line
+ options.
+ This list is also always displayed whenever
+ the <literal>-H</literal> option is used.
+
+ </para>
+
+ </section>
+
+ <section>
+ <title>Controlling How &SCons; Prints Build Commands: the <envar>$*COMSTR</envar> Variables</title>
+
+ <para>
+
+ Sometimes the commands executed
+ to compile object files or link programs
+ (or build other targets)
+ can get very long,
+ long enough to make it difficult for users
+ to distinguish error messages or
+ other important build output
+ from the commands themselves.
+ All of the default <envar>$*COM</envar> variables
+ that specify the command lines
+ used to build various types of target files
+ have a corresponding <envar>$*COMSTR</envar> variable
+ that can be set to an alternative
+ string that will be displayed
+ when the target is built.
+
+ </para>
+
+ <para>
+
+ For example, suppose you want to
+ have &SCons; display a
+ <literal>"Compiling"</literal>
+ message whenever it's compiling an object file,
+ and a
+ <literal>"Linking"</literal>
+ when it's linking an executable.
+ You could write a &SConstruct; file
+ that looks like:
+
+ </para>
+
+ <scons_example name="COMSTR">
+ <file name="SConstruct" printme="1">
+ env = Environment(CCCOMSTR = "Compiling $TARGET",
+ LINKCOMSTR = "Linking $TARGET")
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ </scons_example>
+
+ <para>
+
+ Which would then yield the output:
+
+ </para>
+
+ <!--
+
+ <scons_output example="COMSTR" os="posix">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ Compiling foo.o
+ Linking foo
+ </screen>
+
+ <para>
+
+ &SCons; performs complete variable substitution
+ on <envar>$*COMSTR</envar> variables,
+ so they have access to all of the
+ standard variables like &cv-TARGET; &cv-SOURCES;, etc.,
+ as well as any construction variables
+ that happen to be configured in
+ the construction environment
+ used to build a specific target.
+
+ </para>
+
+ <para>
+
+ Of course, sometimes it's still important to
+ be able to see the exact command
+ that &SCons; will execute to build a target.
+ For example, you may simply need to verify
+ that &SCons; is configured to supply
+ the right options to the compiler,
+ or a developer may want to
+ cut-and-paste a comiloe command
+ to add a few options
+ for a custom test.
+
+ </para>
+
+ <para>
+
+ One common way to give users
+ control over whether or not
+ &SCons; should print the actual command line
+ or a short, configured summary
+ is to add support for a
+ <varname>VERBOSE</varname>
+ command-line variable to your &SConstruct; file.
+ A simple configuration for this might look like:
+
+ </para>
+
+ <scons_example name="COMSTR-VERBOSE">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ if ARGUMENTS.get('VERBOSE') != "1':
+ env['CCCOMSTR'] = "Compiling $TARGET"
+ env['LINKCOMSTR'] = "Linking $TARGET"
+ env.Program('foo.c')
+ </file>
+ <file name="foo.c">
+ foo.c
+ </file>
+ </scons_example>
+
+ <para>
+
+
+ By only setting the appropriate
+ <envar>$*COMSTR</envar> variables
+ if the user specifies
+ <literal>VERBOSE=1</literal>
+ on the command line,
+ the user has control
+ over how &SCons;
+ displays these particular command lines:
+
+ </para>
+
+ <!--
+
+ <scons_output example="COMSTR-VERBOSE" os="posix">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q -c</scons_output_command>
+ <scons_output_command>scons -Q VERBOSE=1</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ Compiling foo.o
+ Linking foo
+ % <userinput>scons -Q -c</userinput>
+ Removed foo.o
+ Removed foo
+ % <userinput>scons -Q VERBOSE=1</userinput>
+ cc -o foo.o -c foo.c
+ cc -o foo foo.o
+ </screen>
+
+ </section>
+
+ <section>
+ <title>Providing Build Progress Output: the &Progress; Function</title>
+
+ <para>
+
+ Another aspect of providing good build output
+ is to give the user feedback
+ about what &SCons; is doing
+ even when nothing is being built at the moment.
+ This can be especially true for large builds
+ when most of the targets are already up-to-date.
+ Because &SCons; can take a long time
+ making absolutely sure that every
+ target is, in fact, up-to-date
+ with respect to a lot of dependency files,
+ it can be easy for users to mistakenly
+ conclude that &SCons; is hung
+ or that there is some other problem with the build.
+
+ </para>
+
+ <para>
+
+ One way to deal with this perception
+ is to configure &SCons; to print something to
+ let the user know what it's "thinking about."
+ The &Progress; function
+ allows you to specify a string
+ that will be printed for every file
+ that &SCons; is "considering"
+ while it is traversing the dependency graph
+ to decide what targets are or are not up-to-date.
+
+ </para>
+
+ <scons_example name="Progress-TARGET">
+ <file name="SConstruct" printme="1">
+ Progress('Evaluating $TARGET\n')
+ Program('f1.c')
+ Program('f2.c')
+ </file>
+ <file name="f1.c">
+ f1.c
+ </file>
+ <file name="f2.c">
+ f2.c
+ </file>
+ </scons_example>
+
+ <para>
+
+ Note that the &Progress; function does not
+ arrange for a newline to be printed automatically
+ at the end of the string (as does the Python
+ <literal>print</literal> statement),
+ and we must specify the
+ <literal>\n</literal>
+ that we want printed at the end of the configured string.
+ This configuration, then,
+ will have &SCons;
+ print that it is <literal>Evaluating</literal>
+ each file that it encounters
+ in turn as it traverses the dependency graph:
+
+ </para>
+
+ <scons_output example="Progress-TARGET" os="posix">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ Of course, normally you don't want to add
+ all of these additional lines to your build output,
+ as that can make it difficult for the user
+ to find errors or other important messages.
+ A more useful way to display
+ this progress might be
+ to have the file names printed
+ directly to the user's screen,
+ not to the same standard output
+ stream where build output is printed,
+ and to use a carriage return character
+ (<literal>\r</literal>)
+ so that each file name gets re-printed on the same line.
+ Such a configuration would look like:
+
+ </para>
+
+ <sconstruct>
+ Progress('$TARGET\r',
+ file=open('/dev/tty', 'w'),
+ overwrite=True)
+ Program('f1.c')
+ Program('f2.c')
+ </sconstruct>
+
+ <para>
+
+ Note that we also specified the
+ <literal>overwrite=True</literal> argument
+ to the &Progress; function,
+ which causes &SCons; to
+ "wipe out" the previous string with space characters
+ before printing the next &Progress; string.
+ Without the
+ <literal>overwrite=True</literal> argument,
+ a shorter file name would not overwrite
+ all of the charactes in a longer file name that
+ precedes it,
+ making it difficult to tell what the
+ actual file name is on the output.
+ Also note that we opened up the
+ <filename>/dev/tty</filename> file
+ for direct access (on POSIX) to
+ the user's screen.
+ On Windows, the equivalent would be to open
+ the <filename>con:</filename> file name.
+
+ </para>
+
+ <para>
+
+ Also, it's important to know that although you can use
+ <literal>$TARGET</literal> to substitute the name of
+ the node in the string,
+ the &Progress; function does <emphasis>not</emphasis>
+ perform general variable substitution
+ (because there's not necessarily a construction
+ environment involved in evaluating a node
+ like a source file, for example).
+
+ </para>
+
+ <para>
+
+ You can also specify a list of strings
+ to the &Progress; function,
+ in which case &SCons; will
+ display each string in turn.
+ This can be used to implement a "spinner"
+ by having &SCons; cycle through a
+ sequence of strings:
+
+ </para>
+
+ <sconstruct>
+ Progress(['-\r', '\\\r', '|\r', '/\r'], interval=5)
+ Program('f1.c')
+ Program('f2.c')
+ </sconstruct>
+
+ <para>
+
+ Note that here we have also used the
+ <literal>interval=</literal>
+ keyword argument to have &SCons;
+ only print a new "spinner" string
+ once every five evaluated nodes.
+ Using an <literal>interval=</literal> count,
+ even with strings that use <literal>$TARGET</literal> like
+ our examples above,
+ can be a good way to lessen the
+ work that &SCons; expends printing &Progress; strings,
+ while still giving the user feedback
+ that indicates &SCons; is still
+ working on evaluating the build.
+
+ </para>
+
+ <para>
+
+ Lastly, you can have direct control
+ over how to print each evaluated node
+ by passing a Python function
+ (or other Python callable)
+ to the &Progress function.
+ Your function will be called
+ for each evaluated node,
+ allowing you to
+ implement more sophisticated logic
+ like adding a counter:
+
+ </para>
+
+ <scons_example name="Progress-callable">
+ <file name="SConstruct" printme="1">
+ screen = open('/dev/tty', 'w')
+ count = 0
+ def progress_function(node)
+ count += 1
+ screen.write('Node %4d: %s\r' % (count, node))
+
+ Progress(progress_function)
+ </file>
+ </scons_example>
+
+ <para>
+
+ Of course, if you choose,
+ you could completely ignore the
+ <varname>node</varname> argument to the function,
+ and just print a count,
+ or anything else you wish.
+
+ </para>
+
+ <para>
+
+ (Note that there's an obvious follow-on question here:
+ how would you find the total number of nodes
+ that <emphasis>will be</emphasis>
+ evaluated so you can tell the user how
+ close the build is to finishing?
+ Unfortunately, in the general case,
+ there isn't a good way to do that,
+ short of having &SCons; evaluate its
+ dependency graph twice,
+ first to count the total and
+ the second time to actually build the targets.
+ This would be necessary because
+ you can't know in advance which
+ target(s) the user actually requested
+ to be built.
+ The entire build may consist of thousands of Nodes,
+ for example,
+ but maybe the user specifically requested
+ that only a single object file be built.)
+
+ </para>
+
+ </section>
+
+ <section>
+ <title>Printing Detailed Build Status: the &GetBuildFailures; Function</title>
+
+ <para>
+
+ SCons, like most build tools, returns zero status to
+ the shell on success and nonzero status on failure.
+ Sometimes it's useful to give more information about
+ the build status at the end of the run, for instance
+ to print an informative message, send an email, or
+ page the poor slob who broke the build.
+
+ </para>
+
+ <para>
+
+ SCons provides a &GetBuildFailures; method that
+ you can use in a python <function>atexit</function> function
+ to get a list of objects describing the actions that failed
+ while attempting to build targets. There can be more
+ than one if you're using <literal>-j</literal>. Here's a
+ simple example:
+
+ </para>
+
+ <scons_example name="gbf1">
+ <file name="SConstruct" printme="1">
+ import atexit
+
+ def print_build_failures():
+ from SCons.Script import GetBuildFailures
+ for bf in GetBuildFailures():
+ print "%s failed: %s" % (bf.node, bf.errstr)
+ atexit.register(print_build_failures)
+ </file>
+ </scons_example>
+
+ <para>
+
+ The <function>atexit.register</function> call
+ registers <function>print_build_failures</function>
+ as an <function>atexit</function> callback, to be called
+ before &SCons; exits. When that function is called,
+ it calls &GetBuildFailures; to fetch the list of failed objects.
+ See the man page
+ for the detailed contents of the returned objects;
+ some of the more useful attributes are
+ <literal>.node</literal>,
+ <literal>.errstr</literal>,
+ <literal>.filename</literal>, and
+ <literal>.command</literal>.
+ The <literal>filename</literal> is not necessarily
+ the same file as the <literal>node</literal>; the
+ <literal>node</literal> is the target that was
+ being built when the error occurred, while the
+ <literal>filename</literal>is the file or dir that
+ actually caused the error.
+ Note: only call &GetBuildFailures; at the end of the
+ build; calling it at any other time is undefined.
+
+ </para>
+
+ <para>
+
+ Here is a more complete example showing how to
+ turn each element of &GetBuildFailures; into a string:
+
+ </para>
+
+ <scons_example name="gbf2">
+ <file name="SConstruct" printme="1">
+ # Make the build fail if we pass fail=1 on the command line
+ if ARGUMENTS.get('fail', 0):
+ Command('target', 'source', ['/bin/false'])
+
+ def bf_to_str(bf):
+ """Convert an element of GetBuildFailures() to a string
+ in a useful way."""
+ import SCons.Errors
+ if bf is None: # unknown targets product None in list
+ return '(unknown tgt)'
+ elif isinstance(bf, SCons.Errors.StopError):
+ return str(bf)
+ elif bf.node:
+ return str(bf.node) + ': ' + bf.errstr
+ elif bf.filename:
+ return bf.filename + ': ' + bf.errstr
+ return 'unknown failure: ' + bf.errstr
+ import atexit
+
+ def build_status():
+ """Convert the build status to a 2-tuple, (status, msg)."""
+ from SCons.Script import GetBuildFailures
+ bf = GetBuildFailures()
+ if bf:
+ # bf is normally a list of build failures; if an element is None,
+ # it's because of a target that scons doesn't know anything about.
+ status = 'failed'
+ failures_message = "\n".join(["Failed building %s" % bf_to_str(x)
+ for x in bf if x is not None])
+ else:
+ # if bf is None, the build completed successfully.
+ status = 'ok'
+ failures_message = ''
+ return (status, failures_message)
+
+ def display_build_status():
+ """Display the build status. Called by atexit.
+ Here you could do all kinds of complicated things."""
+ status, failures_message = build_status()
+ if status == 'failed':
+ print "FAILED!!!!" # could display alert, ring bell, etc.
+ elif status == 'ok':
+ print "Build succeeded."
+ print failures_message
+
+ atexit.register(display_build_status)
+ </file>
+ </scons_example>
+
+ <para>
+
+ When this runs, you'll see the appropriate output:
+
+ </para>
+
+ <scons_output example="gbf2">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q fail=1</scons_output_command>
+ </scons_output>
+
+ </section>
--- /dev/null
+<!--
+
+ __COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+ <para>
+
+ A key aspect of creating a usable build configuration
+ is providing good output from the build
+ so its users can readily understand
+ what the build is doing
+ and get information about how to control the build.
+ &SCons; provides several ways of
+ controlling output from the build configuration
+ to help make the build
+ more useful and understandable.
+
+ </para>
+
+ <section>
+ <title>Providing Build Help: the &Help; Function</title>
+
+ <para>
+
+ It's often very useful to be able to give
+ users some help that describes the
+ specific targets, build options, etc.,
+ that can be used for your build.
+ &SCons; provides the &Help; function
+ to allow you to specify this help text:
+
+ </para>
+
+ <programlisting>
+ Help("""
+ Type: 'scons program' to build the production program,
+ 'scons debug' to build the debug version.
+ """)
+ </programlisting>
+
+ <para>
+
+ (Note the above use of the Python triple-quote syntax,
+ which comes in very handy for
+ specifying multi-line strings like help text.)
+
+ </para>
+
+ <para>
+
+ When the &SConstruct; or &SConscript; files
+ contain such a call to the &Help; function,
+ the specified help text will be displayed in response to
+ the &SCons; <literal>-h</literal> option:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -h</userinput>
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+
+ Type: 'scons program' to build the production program,
+ 'scons debug' to build the debug version.
+
+ Use scons -H for help about command-line options.
+ </screen>
+
+ <para>
+
+ The &SConscript; files may contain
+ multiple calls to the &Help; function,
+ in which case the specified text(s)
+ will be concatenated when displayed.
+ This allows you to split up the
+ help text across multiple &SConscript; files.
+ In this situation, the order in
+ which the &SConscript; files are called
+ will determine the order in which the &Help; functions are called,
+ which will determine the order in which
+ the various bits of text will get concatenated.
+
+ </para>
+
+ <para>
+
+ Another use would be to make the help text conditional
+ on some variable.
+ For example, suppose you only want to display
+ a line about building a Windows-only
+ version of a program when actually
+ run on Windows.
+ The following &SConstruct; file:
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+
+ Help("\nType: 'scons program' to build the production program.\n")
+
+ if env['PLATFORM'] == 'win32':
+ Help("\nType: 'scons windebug' to build the Windows debug version.\n")
+ </programlisting>
+
+ <para>
+
+ Will display the complete help text on Windows:
+
+ </para>
+
+ <screen>
+ C:\><userinput>scons -h</userinput>
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+
+ Type: 'scons program' to build the production program.
+
+ Type: 'scons windebug' to build the Windows debug version.
+
+ Use scons -H for help about command-line options.
+ </screen>
+
+ <para>
+
+ But only show the relevant option on a Linux or UNIX system:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -h</userinput>
+ scons: Reading SConscript files ...
+ scons: done reading SConscript files.
+
+ Type: 'scons program' to build the production program.
+
+ Use scons -H for help about command-line options.
+ </screen>
+
+ <para>
+
+ If there is no &Help; text in the &SConstruct; or
+ &SConscript; files,
+ &SCons; will revert to displaying its
+ standard list that describes the &SCons; command-line
+ options.
+ This list is also always displayed whenever
+ the <literal>-H</literal> option is used.
+
+ </para>
+
+ </section>
+
+ <section>
+ <title>Controlling How &SCons; Prints Build Commands: the <envar>$*COMSTR</envar> Variables</title>
+
+ <para>
+
+ Sometimes the commands executed
+ to compile object files or link programs
+ (or build other targets)
+ can get very long,
+ long enough to make it difficult for users
+ to distinguish error messages or
+ other important build output
+ from the commands themselves.
+ All of the default <envar>$*COM</envar> variables
+ that specify the command lines
+ used to build various types of target files
+ have a corresponding <envar>$*COMSTR</envar> variable
+ that can be set to an alternative
+ string that will be displayed
+ when the target is built.
+
+ </para>
+
+ <para>
+
+ For example, suppose you want to
+ have &SCons; display a
+ <literal>"Compiling"</literal>
+ message whenever it's compiling an object file,
+ and a
+ <literal>"Linking"</literal>
+ when it's linking an executable.
+ You could write a &SConstruct; file
+ that looks like:
+
+ </para>
+
+ <programlisting>
+ env = Environment(CCCOMSTR = "Compiling $TARGET",
+ LINKCOMSTR = "Linking $TARGET")
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+ Which would then yield the output:
+
+ </para>
+
+ <!--
+
+ <scons_output example="COMSTR" os="posix">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ Compiling foo.o
+ Linking foo
+ </screen>
+
+ <para>
+
+ &SCons; performs complete variable substitution
+ on <envar>$*COMSTR</envar> variables,
+ so they have access to all of the
+ standard variables like &cv-TARGET; &cv-SOURCES;, etc.,
+ as well as any construction variables
+ that happen to be configured in
+ the construction environment
+ used to build a specific target.
+
+ </para>
+
+ <para>
+
+ Of course, sometimes it's still important to
+ be able to see the exact command
+ that &SCons; will execute to build a target.
+ For example, you may simply need to verify
+ that &SCons; is configured to supply
+ the right options to the compiler,
+ or a developer may want to
+ cut-and-paste a comiloe command
+ to add a few options
+ for a custom test.
+
+ </para>
+
+ <para>
+
+ One common way to give users
+ control over whether or not
+ &SCons; should print the actual command line
+ or a short, configured summary
+ is to add support for a
+ <varname>VERBOSE</varname>
+ command-line variable to your &SConstruct; file.
+ A simple configuration for this might look like:
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ if ARGUMENTS.get('VERBOSE') != "1':
+ env['CCCOMSTR'] = "Compiling $TARGET"
+ env['LINKCOMSTR'] = "Linking $TARGET"
+ env.Program('foo.c')
+ </programlisting>
+
+ <para>
+
+
+ By only setting the appropriate
+ <envar>$*COMSTR</envar> variables
+ if the user specifies
+ <literal>VERBOSE=1</literal>
+ on the command line,
+ the user has control
+ over how &SCons;
+ displays these particular command lines:
+
+ </para>
+
+ <!--
+
+ <scons_output example="COMSTR-VERBOSE" os="posix">
+ <scons_output_command>scons -Q</scons_output_command>
+ <scons_output_command>scons -Q -c</scons_output_command>
+ <scons_output_command>scons -Q VERBOSE=1</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ Compiling foo.o
+ Linking foo
+ % <userinput>scons -Q -c</userinput>
+ Removed foo.o
+ Removed foo
+ % <userinput>scons -Q VERBOSE=1</userinput>
+ cc -o foo.o -c foo.c
+ cc -o foo foo.o
+ </screen>
+
+ </section>
+
+ <section>
+ <title>Providing Build Progress Output: the &Progress; Function</title>
+
+ <para>
+
+ Another aspect of providing good build output
+ is to give the user feedback
+ about what &SCons; is doing
+ even when nothing is being built at the moment.
+ This can be especially true for large builds
+ when most of the targets are already up-to-date.
+ Because &SCons; can take a long time
+ making absolutely sure that every
+ target is, in fact, up-to-date
+ with respect to a lot of dependency files,
+ it can be easy for users to mistakenly
+ conclude that &SCons; is hung
+ or that there is some other problem with the build.
+
+ </para>
+
+ <para>
+
+ One way to deal with this perception
+ is to configure &SCons; to print something to
+ let the user know what it's "thinking about."
+ The &Progress; function
+ allows you to specify a string
+ that will be printed for every file
+ that &SCons; is "considering"
+ while it is traversing the dependency graph
+ to decide what targets are or are not up-to-date.
+
+ </para>
+
+ <programlisting>
+ Progress('Evaluating $TARGET\n')
+ Program('f1.c')
+ Program('f2.c')
+ </programlisting>
+
+ <para>
+
+ Note that the &Progress; function does not
+ arrange for a newline to be printed automatically
+ at the end of the string (as does the Python
+ <literal>print</literal> statement),
+ and we must specify the
+ <literal>\n</literal>
+ that we want printed at the end of the configured string.
+ This configuration, then,
+ will have &SCons;
+ print that it is <literal>Evaluating</literal>
+ each file that it encounters
+ in turn as it traverses the dependency graph:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ Evaluating SConstruct
+ Evaluating f1.c
+ Evaluating f1.o
+ cc -o f1.o -c f1.c
+ Evaluating f1
+ cc -o f1 f1.o
+ Evaluating f2.c
+ Evaluating f2.o
+ cc -o f2.o -c f2.c
+ Evaluating f2
+ cc -o f2 f2.o
+ Evaluating .
+ </screen>
+
+ <para>
+
+ Of course, normally you don't want to add
+ all of these additional lines to your build output,
+ as that can make it difficult for the user
+ to find errors or other important messages.
+ A more useful way to display
+ this progress might be
+ to have the file names printed
+ directly to the user's screen,
+ not to the same standard output
+ stream where build output is printed,
+ and to use a carriage return character
+ (<literal>\r</literal>)
+ so that each file name gets re-printed on the same line.
+ Such a configuration would look like:
+
+ </para>
+
+ <programlisting>
+ Progress('$TARGET\r',
+ file=open('/dev/tty', 'w'),
+ overwrite=True)
+ Program('f1.c')
+ Program('f2.c')
+ </programlisting>
+
+ <para>
+
+ Note that we also specified the
+ <literal>overwrite=True</literal> argument
+ to the &Progress; function,
+ which causes &SCons; to
+ "wipe out" the previous string with space characters
+ before printing the next &Progress; string.
+ Without the
+ <literal>overwrite=True</literal> argument,
+ a shorter file name would not overwrite
+ all of the charactes in a longer file name that
+ precedes it,
+ making it difficult to tell what the
+ actual file name is on the output.
+ Also note that we opened up the
+ <filename>/dev/tty</filename> file
+ for direct access (on POSIX) to
+ the user's screen.
+ On Windows, the equivalent would be to open
+ the <filename>con:</filename> file name.
+
+ </para>
+
+ <para>
+
+ Also, it's important to know that although you can use
+ <literal>$TARGET</literal> to substitute the name of
+ the node in the string,
+ the &Progress; function does <emphasis>not</emphasis>
+ perform general variable substitution
+ (because there's not necessarily a construction
+ environment involved in evaluating a node
+ like a source file, for example).
+
+ </para>
+
+ <para>
+
+ You can also specify a list of strings
+ to the &Progress; function,
+ in which case &SCons; will
+ display each string in turn.
+ This can be used to implement a "spinner"
+ by having &SCons; cycle through a
+ sequence of strings:
+
+ </para>
+
+ <programlisting>
+ Progress(['-\r', '\\\r', '|\r', '/\r'], interval=5)
+ Program('f1.c')
+ Program('f2.c')
+ </programlisting>
+
+ <para>
+
+ Note that here we have also used the
+ <literal>interval=</literal>
+ keyword argument to have &SCons;
+ only print a new "spinner" string
+ once every five evaluated nodes.
+ Using an <literal>interval=</literal> count,
+ even with strings that use <literal>$TARGET</literal> like
+ our examples above,
+ can be a good way to lessen the
+ work that &SCons; expends printing &Progress; strings,
+ while still giving the user feedback
+ that indicates &SCons; is still
+ working on evaluating the build.
+
+ </para>
+
+ <para>
+
+ Lastly, you can have direct control
+ over how to print each evaluated node
+ by passing a Python function
+ (or other Python callable)
+ to the &Progress; function.
+ Your function will be called
+ for each evaluated node,
+ allowing you to
+ implement more sophisticated logic
+ like adding a counter:
+
+ </para>
+
+ <programlisting>
+ screen = open('/dev/tty', 'w')
+ count = 0
+ def progress_function(node)
+ count += 1
+ screen.write('Node %4d: %s\r' % (count, node))
+
+ Progress(progress_function)
+ </programlisting>
+
+ <para>
+
+ Of course, if you choose,
+ you could completely ignore the
+ <varname>node</varname> argument to the function,
+ and just print a count,
+ or anything else you wish.
+
+ </para>
+
+ <para>
+
+ (Note that there's an obvious follow-on question here:
+ how would you find the total number of nodes
+ that <emphasis>will be</emphasis>
+ evaluated so you can tell the user how
+ close the build is to finishing?
+ Unfortunately, in the general case,
+ there isn't a good way to do that,
+ short of having &SCons; evaluate its
+ dependency graph twice,
+ first to count the total and
+ the second time to actually build the targets.
+ This would be necessary because
+ you can't know in advance which
+ target(s) the user actually requested
+ to be built.
+ The entire build may consist of thousands of Nodes,
+ for example,
+ but maybe the user specifically requested
+ that only a single object file be built.)
+
+ </para>
+
+ </section>
+
+ <section>
+ <title>Printing Detailed Build Status: the &GetBuildFailures; Function</title>
+
+ <para>
+
+ SCons, like most build tools, returns zero status to
+ the shell on success and nonzero status on failure.
+ Sometimes it's useful to give more information about
+ the build status at the end of the run, for instance
+ to print an informative message, send an email, or
+ page the poor slob who broke the build.
+
+ </para>
+
+ <para>
+
+ SCons provides a &GetBuildFailures; method that
+ you can use in a python <function>atexit</function> function
+ to get a list of objects describing the actions that failed
+ while attempting to build targets. There can be more
+ than one if you're using <literal>-j</literal>. Here's a
+ simple example:
+
+ </para>
+
+ <programlisting>
+ import atexit
+
+ def print_build_failures():
+ from SCons.Script import GetBuildFailures
+ for bf in GetBuildFailures():
+ print "%s failed: %s" % (bf.node, bf.errstr)
+ atexit.register(print_build_failures)
+ </programlisting>
+
+ <para>
+
+ The <function>atexit.register</function> call
+ registers <function>print_build_failures</function>
+ as an <function>atexit</function> callback, to be called
+ before &SCons; exits. When that function is called,
+ it calls &GetBuildFailures; to fetch the list of failed objects.
+ See the man page
+ for the detailed contents of the returned objects;
+ some of the more useful attributes are
+ <literal>.node</literal>,
+ <literal>.errstr</literal>,
+ <literal>.filename</literal>, and
+ <literal>.command</literal>.
+ The <literal>filename</literal> is not necessarily
+ the same file as the <literal>node</literal>; the
+ <literal>node</literal> is the target that was
+ being built when the error occurred, while the
+ <literal>filename</literal>is the file or dir that
+ actually caused the error.
+ Note: only call &GetBuildFailures; at the end of the
+ build; calling it at any other time is undefined.
+
+ </para>
+
+ <para>
+
+ Here is a more complete example showing how to
+ turn each element of &GetBuildFailures; into a string:
+
+ </para>
+
+ <programlisting>
+ # Make the build fail if we pass fail=1 on the command line
+ if ARGUMENTS.get('fail', 0):
+ Command('target', 'source', ['/bin/false'])
+
+ def bf_to_str(bf):
+ """Convert an element of GetBuildFailures() to a string
+ in a useful way."""
+ import SCons.Errors
+ if bf is None: # unknown targets product None in list
+ return '(unknown tgt)'
+ elif isinstance(bf, SCons.Errors.StopError):
+ return str(bf)
+ elif bf.node:
+ return str(bf.node) + ': ' + bf.errstr
+ elif bf.filename:
+ return bf.filename + ': ' + bf.errstr
+ return 'unknown failure: ' + bf.errstr
+ import atexit
+
+ def build_status():
+ """Convert the build status to a 2-tuple, (status, msg)."""
+ from SCons.Script import GetBuildFailures
+ bf = GetBuildFailures()
+ if bf:
+ # bf is normally a list of build failures; if an element is None,
+ # it's because of a target that scons doesn't know anything about.
+ status = 'failed'
+ failures_message = "\n".join(["Failed building %s" % bf_to_str(x)
+ for x in bf if x is not None])
+ else:
+ # if bf is None, the build completed successfully.
+ status = 'ok'
+ failures_message = ''
+ return (status, failures_message)
+
+ def display_build_status():
+ """Display the build status. Called by atexit.
+ Here you could do all kinds of complicated things."""
+ status, failures_message = build_status()
+ if status == 'failed':
+ print "FAILED!!!!" # could display alert, ring bell, etc.
+ elif status == 'ok':
+ print "Build succeeded."
+ print failures_message
+
+ atexit.register(display_build_status)
+ </programlisting>
+
+ <para>
+
+ When this runs, you'll see the appropriate output:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ scons: `.' is up to date.
+ Build succeeded.
+ % <userinput>scons -Q fail=1</userinput>
+ scons: *** Source `source' not found, needed by target `target'. Stop.
+ FAILED!!!!
+ Failed building Source `source' not found, needed by target `target'.
+ </screen>
+
+ </section>
<para>
- Configuring the right options to build programs to work with the
- libraries--especially shared libraries--installed on a POSIX system
- can be very complicated.
- Various utilies with names that end in <filename>config</filename>
- can return command-line options for the
- GNU Compiler Collection
+ Configuring the right options to build programs to work with
+ libraries--especially shared libraries--that are available
+ on POSIX systems can be very complicated.
+ To help this situation,
+ various utilies with names that end in <filename>config</filename>
+ return the command-line options for the GNU Compiler Collection (GCC)
+ that are needed to use these libraries;
+ for example, the command-line options
+ to use a library named <filename>lib</filename>
+ would be found by calling a utility named <filename>lib-config</filename>.
+
+ </para>
+
+ <para>
+
+ A more recent convention is that these options
+ are available from the generic <filename>pkg-config</filename> program,
+ which has common framework, error handling, and the like,
+ so that all the package creator has to do is provide the set of strings
+ for his particular package.
</para>
<para>
&SCons; construction environments have a &ParseConfig; method
- that executes a utility and configures
- the appropriate construction variables
+ that executes a <filename>*config</filename> utility
+ (either <filename>pkg-config</filename> or a
+ more specific utility)
+ and configures the appropriate construction variables
in the environment
based on the command-line options
returned by the specified command.
</para>
- </para>
-
<scons_example name="ParseConfig1">
<file name="SConstruct" printme="1">
env = Environment()
- env.ParseConfig("pkg-config x11")
- </file>
- <file name="f1.c">
- int f1() { }
- </file>
- <file name="f2.c">
- int f2() { }
- </file>
- <file name="f3.c">
- int f3() { }
+ env['CPPPATH'] = ['/lib/compat']
+ env.ParseConfig("pkg-config x11 --cflags --libs")
+ print env['CPPPATH']
</file>
</scons_example>
<para>
- &SCons; will execute the specified command string
- and XXX
+ &SCons; will execute the specified command string,
+ parse the resultant flags,
+ and add the flags to the appropriate environment variables.
</para>
<para>
- XXX
+ In the example above, &SCons; has added the include directory to
+ <varname>CPPPATH</varname>.
+ (Depending upon what other flags are emitted by the
+ <filename>pkg-config</filename> command,
+ other variables may have been extended as well.)
</para>
+
+ <para>
+
+ Note that the options are merged with existing options using
+ the &MergeFlags; method,
+ so that each option only occurs once in the construction variable:
+
+ </para>
+
+ <scons_example name="ParseConfig2">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ env.ParseConfig("pkg-config x11 --cflags --libs")
+ env.ParseConfig("pkg-config x11 --cflags --libs")
+ print env['CPPPATH']
+ </file>
+ </scons_example>
+
+ <scons_output example="ParseConfig2">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
<para>
- Configuring the right options to build programs to work with the
- libraries--especially shared libraries--installed on a POSIX system
- can be very complicated.
- Various utilies with names that end in <filename>config</filename>
- can return command-line options for the
- GNU Compiler Collection
+ Configuring the right options to build programs to work with
+ libraries--especially shared libraries--that are available
+ on POSIX systems can be very complicated.
+ To help this situation,
+ various utilies with names that end in <filename>config</filename>
+ return the command-line options for the GNU Compiler Collection (GCC)
+ that are needed to use these libraries;
+ for example, the command-line options
+ to use a library named <filename>lib</filename>
+ would be found by calling a utility named <filename>lib-config</filename>.
+
+ </para>
+
+ <para>
+
+ A more recent convention is that these options
+ are available from the generic <filename>pkg-config</filename> program,
+ which has common framework, error handling, and the like,
+ so that all the package creator has to do is provide the set of strings
+ for his particular package.
</para>
<para>
&SCons; construction environments have a &ParseConfig; method
- that executes a utility and configures
- the appropriate construction variables
+ that executes a <filename>*config</filename> utility
+ (either <filename>pkg-config</filename> or a
+ more specific utility)
+ and configures the appropriate construction variables
in the environment
based on the command-line options
returned by the specified command.
</para>
- </para>
-
<programlisting>
env = Environment()
- env.ParseConfig("pkg-config x11")
+ env['CPPPATH'] = ['/lib/compat']
+ env.ParseConfig("pkg-config x11 --cflags --libs")
+ print env['CPPPATH']
</programlisting>
<para>
- &SCons; will execute the specified command string
- and XXX
+ &SCons; will execute the specified command string,
+ parse the resultant flags,
+ and add the flags to the appropriate environment variables.
</para>
<screen>
% <userinput>scons -Q</userinput>
+ ['/lib/compat', '/usr/X11/include']
scons: `.' is up to date.
</screen>
<para>
- XXX
+ In the example above, &SCons; has added the include directory to
+ <varname>CPPPATH</varname>.
+ (Depending upon what other flags are emitted by the
+ <filename>pkg-config</filename> command,
+ other variables may have been extended as well.)
</para>
+
+ <para>
+
+ Note that the options are merged with existing options using
+ the &MergeFlags; method,
+ so that each option only occurs once in the construction variable:
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ env.ParseConfig("pkg-config x11 --cflags --libs")
+ env.ParseConfig("pkg-config x11 --cflags --libs")
+ print env['CPPPATH']
+ </programlisting>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ ['/usr/X11/include']
+ scons: `.' is up to date.
+ </screen>
--- /dev/null
+<!--
+
+ __COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+ <para>
+
+ &SCons; has a bewildering array of construction variables
+ for different types of options when building programs.
+ Sometimes you may not know exactly which variable
+ should be used for a particular option.
+
+ </para>
+
+ <para>
+
+ &SCons; construction environments have a &ParseFlags; method
+ that takes a set of typical command-line options
+ and distrbutes them into the appropriate construction variables.
+ Historically, it was created to support the &ParseConfig; method,
+ so it focuses on options used by the GNU Compiler Collection (GCC)
+ for the C and C++ toolchains.
+
+ </para>
+
+ <para>
+
+ &ParseFlags; returns a dictionary containing the options
+ distributed into their respective construction variables.
+ Normally, this dictionary would be passed to &MergeFlags;
+ to merge the options into a &consenv;,
+ but the dictionary can be edited if desired to provide
+ additional functionality.
+ (Note that if the flags are not going to be edited,
+ calling &MergeFlags; with the options directly
+ will avoid an additional step.)
+
+ </para>
+
+ <scons_example name="ParseFlags1">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ d = env.ParseFlags("-I/opt/include -L/opt/lib -lfoo")
+ l = d.items()
+ l.sort()
+ for k,v in l:
+ if v:
+ print k, v
+ env.MergeFlags(d)
+ env.Program('f1.c')
+ </file>
+ <file name="f1.c">
+ int main() { return 0; }
+ </file>
+ </scons_example>
+
+ <scons_output example="ParseFlags1" os="posix">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ Note that if the options are limited to generic types
+ like those above,
+ they will be correctly translated for other platform types:
+
+ </para>
+
+ <scons_output example="ParseFlags1" os="win32">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ Since the assumption is that the flags are used for the GCC toolchain,
+ unrecognized flags are placed in &cv-link-CCFLAGS;
+ so they will be used for both C and C++ compiles:
+
+ </para>
+
+ <scons_example name="ParseFlags2">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ d = env.ParseFlags("-whatever")
+ l = d.items()
+ l.sort()
+ for k,v in l:
+ if v:
+ print k, v
+ env.MergeFlags(d)
+ env.Program('f1.c')
+ </file>
+ <file name="f1.c">
+ int main() { return 0; }
+ </file>
+ </scons_example>
+
+ <scons_output example="ParseFlags2">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ &ParseFlags; will also accept a (recursive) list of strings as input;
+ the list is flattened before the strings are processed:
+
+ </para>
+
+ <scons_example name="ParseFlags3">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ d = env.ParseFlags(["-I/opt/include", ["-L/opt/lib", "-lfoo"]])
+ l = d.items()
+ l.sort()
+ for k,v in l:
+ if v:
+ print k, v
+ env.MergeFlags(d)
+ env.Program('f1.c')
+ </file>
+ <file name="f1.c">
+ int main() { return 0; }
+ </file>
+ </scons_example>
+
+ <scons_output example="ParseFlags3">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ If a string begins with a "!" (an exclamation mark, often called a bang),
+ the string is passed to the shell for execution.
+ The output of the command is then parsed:
+
+ </para>
+
+ <scons_example name="ParseFlags4">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ d = env.ParseFlags(["!echo -I/opt/include", "!echo -L/opt/lib", "-lfoo"])
+ l = d.items()
+ l.sort()
+ for k,v in l:
+ if v:
+ print k, v
+ env.MergeFlags(d)
+ env.Program('f1.c')
+ </file>
+ <file name="f1.c">
+ int main() { return 0; }
+ </file>
+ </scons_example>
+
+ <scons_output example="ParseFlags4">
+ <scons_output_command>scons -Q</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ &ParseFlags; is regularly updated for new options;
+ consult the man page for details about those currently recognized.
+
+ </para>
--- /dev/null
+<!--
+
+ __COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+ <para>
+
+ &SCons; has a bewildering array of construction variables
+ for different types of options when building programs.
+ Sometimes you may not know exactly which variable
+ should be used for a particular option.
+
+ </para>
+
+ <para>
+
+ &SCons; construction environments have a &ParseFlags; method
+ that takes a set of typical command-line options
+ and distrbutes them into the appropriate construction variables.
+ Historically, it was created to support the &ParseConfig; method,
+ so it focuses on options used by the GNU Compiler Collection (GCC)
+ for the C and C++ toolchains.
+
+ </para>
+
+ <para>
+
+ &ParseFlags; returns a dictionary containing the options
+ distributed into their respective construction variables.
+ Normally, this dictionary would be passed to &MergeFlags;
+ to merge the options into a &consenv;,
+ but the dictionary can be edited if desired to provide
+ additional functionality.
+ (Note that if the flags are not going to be edited,
+ calling &MergeFlags; with the options directly
+ will avoid an additional step.)
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ d = env.ParseFlags("-I/opt/include -L/opt/lib -lfoo")
+ l = d.items()
+ l.sort()
+ for k,v in l:
+ if v:
+ print k, v
+ env.MergeFlags(d)
+ env.Program('f1.c')
+ </programlisting>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ CPPPATH ['/opt/include']
+ LIBPATH ['/opt/lib']
+ LIBS ['foo']
+ cc -o f1.o -c -I/opt/include f1.c
+ cc -o f1 f1.o -L/opt/lib -lfoo
+ </screen>
+
+ <para>
+
+ Note that if the options are limited to generic types
+ like those above,
+ they will be correctly translated for other platform types:
+
+ </para>
+
+ <screen>
+ C:\><userinput>scons -Q</userinput>
+ CPPPATH ['/opt/include']
+ LIBPATH ['/opt/lib']
+ LIBS ['foo']
+ cl /nologo /I\opt\include /c f1.c /Fof1.obj
+ link /nologo /OUT:f1.exe /LIBPATH:\opt\lib foo.lib f1.obj
+ </screen>
+
+ <para>
+
+ Since the assumption is that the flags are used for the GCC toolchain,
+ unrecognized flags are placed in &cv-link-CCFLAGS;
+ so they will be used for both C and C++ compiles:
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ d = env.ParseFlags("-whatever")
+ l = d.items()
+ l.sort()
+ for k,v in l:
+ if v:
+ print k, v
+ env.MergeFlags(d)
+ env.Program('f1.c')
+ </programlisting>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ CCFLAGS -whatever
+ cc -o f1.o -c -whatever f1.c
+ cc -o f1 f1.o
+ </screen>
+
+ <para>
+
+ &ParseFlags; will also accept a (recursive) list of strings as input;
+ the list is flattened before the strings are processed:
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ d = env.ParseFlags(["-I/opt/include", ["-L/opt/lib", "-lfoo"]])
+ l = d.items()
+ l.sort()
+ for k,v in l:
+ if v:
+ print k, v
+ env.MergeFlags(d)
+ env.Program('f1.c')
+ </programlisting>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ CPPPATH ['/opt/include']
+ LIBPATH ['/opt/lib']
+ LIBS ['foo']
+ cc -o f1.o -c -I/opt/include f1.c
+ cc -o f1 f1.o -L/opt/lib -lfoo
+ </screen>
+
+ <para>
+
+ If a string begins with a "!" (an exclamation mark, often called a bang),
+ the string is passed to the shell for execution.
+ The output of the command is then parsed:
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ d = env.ParseFlags(["!echo -I/opt/include", "!echo -L/opt/lib", "-lfoo"])
+ l = d.items()
+ l.sort()
+ for k,v in l:
+ if v:
+ print k, v
+ env.MergeFlags(d)
+ env.Program('f1.c')
+ </programlisting>
+
+ <screen>
+ % <userinput>scons -Q</userinput>
+ CPPPATH ['/opt/include']
+ LIBPATH ['/opt/lib']
+ LIBS ['foo']
+ cc -o f1.o -c -I/opt/include f1.c
+ cc -o f1 f1.o -L/opt/lib -lfoo
+ </screen>
+
+ <para>
+
+ &ParseFlags; is regularly updated for new options;
+ consult the man page for details about those currently recognized.
+
+ </para>
</section>
<section>
- <title>Using Glob() with &VariantDir;</title>
+ <title>Using &Glob; with &VariantDir;</title>
<para>
- The Glob() file name pattern matching function
+ The &Glob; file name pattern matching function
works just as usual when using &VariantDir;.
For example, if the
<filename>src/SConscript</filename>
<para>
Then with the same &SConstruct; file as in the previous section,
- and source files f1.c and f2.c in src, we would see the following
- output:
+ and source files <filename>f1.c</filename>
+ and <filename>f2.c</filename> in src,
+ we would see the following output:
</para>
<para>
- The Glob function returns Nodes in the build/ tree, as
- you'd expect.
+ The &Glob; function returns Nodes in the
+ <filename>build/</filename> tree, as you'd expect.
</para>
</section>
<section>
- <title>Using Glob() with &VariantDir;</title>
+ <title>Using &Glob; with &VariantDir;</title>
<para>
- The Glob() file name pattern matching function
+ The &Glob; file name pattern matching function
works just as usual when using &VariantDir;.
For example, if the
<filename>src/SConscript</filename>
<para>
Then with the same &SConstruct; file as in the previous section,
- and source files f1.c and f2.c in src, we would see the following
- output:
+ and source files <filename>f1.c</filename>
+ and <filename>f2.c</filename> in src,
+ we would see the following output:
</para>
<para>
- The Glob function returns Nodes in the build/ tree, as
- you'd expect.
+ The &Glob; function returns Nodes in the
+ <filename>build/</filename> tree, as you'd expect.
</para>
--- /dev/null
+<!--
+
+ __COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+ <!--
+
+ <para>
+
+ If &SCons; is unaware that a build step produces an extra file,
+ the &SideEffect; method can be used to identify it,
+ so that the file can be used as a dependency in subsequent build steps.
+ However, the primary use for the &SideEffect; method
+ is to prevent two build steps from simultaneously modifying the same file.
+
+ </para>
+
+ TODO: currently doesn't work due to issue #2154:
+ http://scons.tigris.org/issues/show_bug.cgi?id=2154
+
+ <para>
+
+ If more than one build step creates or manipulates the same file,
+ it can cause unpleasant results if both build steps are run at the same time.
+ The shared file is declared as a side-effect of building the primary targets
+ and &SCons; will prevent the two build steps from running in parallel.
+
+ </para>
+
+ <para>
+
+ In this example, the <filename>SConscript</filename> uses
+ &SideEffect; to inform &SCons; about the additional output file.
+
+ </para>
+
+ <scons_example name="SideEffectSimple">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ f2 = env.Command('file2', 'log', Copy('$TARGET', '$SOURCE'))
+ f1 = env.Command('file1', [],
+ 'echo >$TARGET data1; echo >log updated file1'))
+ env.SideEffect('log', env.Command('file1', [],
+ 'echo >$TARGET data1; echo >log updated file1'))
+ </file>
+ </scons_example>
+
+ <para>
+
+ Even when run in parallel mode, &SCons; will run the two steps in order:
+
+ </para>
+
+ <scons_output example="SideEffectSimple">
+ <scons_output_command>scons -Q --jobs=2</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <para>
+
+ Sometimes a program the you need to call
+ to build a target file
+ will also update another file,
+ such as a log file describing what the program
+ does while building the target.
+ For example, we the folowing configuration
+ would have &SCons; invoke a hypothetical
+ script named <application>build</application>
+ (in the local directory)
+ with command-line arguments that write
+ log information to a common
+ <filename>logfile.txt</filename> file:
+
+ </para>
+
+ <screen>
+ env = Environment()
+ env.Command('file1.out', 'file.in',
+ './build --log logfile.txt $SOURCE $TARGET')
+ env.Command('file2.out', 'file.in',
+ './build --log logfile.txt $SOURCE $TARGET')
+ <screen>
+
+ <para>
+
+ This can cause problems when running
+ the build in parallel if
+ &SCons; decides to update both targets
+ by running both program invocations at the same time.
+ The multiple program invocations
+ may interfere with each other
+ writing to the common log file,
+ leading at best to intermixed output in the log file,
+ and at worst to an actual failed build
+ (on a system like Windows, for example,
+ where only one process at a time can open the log file for writing).
+
+ </para>
+
+ <para>
+
+ We can make sure that &SCons; does not
+ run these <application>build</application>
+ commands at the same time
+ by using the &SideEffect; function
+ to specify that updating
+ the <filename>logfile.txt</filename> file
+ is a side effect of building the specified
+ <filename>file1</filename>
+ and
+ <filename>file2</filename>
+ target files:
+
+ </para>
+
+ <scons_example name="SideEffectShared">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ f1 = env.Command('file1.out', 'file1.in',
+ './build --log logfile.txt $SOURCE $TARGET')
+ f2 = env.Command('file2.out', 'file2.in',
+ './build --log logfile.txt $SOURCE $TARGET')
+ env.SideEffect('logfile.txt', f1 + f2)
+ </file>
+ <file name="file1.in">file1.in</file>
+ <file name="file2.in">file2.in</file>
+ <file name="build" chmod="0755">
+ cat
+ </file>
+ </scons_example>
+
+ <para>
+
+ </para>
+
+ <para>
+
+ This makes sure the the two
+ <application>./build</application> steps are run sequentially,
+ even withthe <filename>--jobs=2</filename> in the command line:
+
+ </para>
+
+ <scons_output example="SideEffectShared">
+ <scons_output_command>scons -Q --jobs=2</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ The &SideEffect; function can be called multiple
+ times for the same side-effect file.
+ Additionally, the name used as a &SideEffect; does not
+ even need to actually exist as a file on disk.
+ &SCons; will still make sure
+ that the relevant targets
+ will be executed sequentially, not in parallel:
+
+ </para>
+
+ <scons_example name="SideEffectParallel">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ f1 = env.Command('file1.out', [], 'echo >$TARGET data1')
+ env.SideEffect('not_really_updated', f1)
+ f2 = env.Command('file2.out', [], 'echo >$TARGET data2')
+ env.SideEffect('not_really_updated', f2)
+ </file>
+ </scons_example>
+
+ <scons_output example="SideEffectParallel">
+ <scons_output_command>scons -Q --jobs=2</scons_output_command>
+ </scons_output>
+
+ <para>
+
+ Note that it might be tempting to
+ use &SideEffect; for additional target files
+ that a command produces.
+ For example, versions the Microsoft Visual C/C++ compiler
+ produce a <filename>foo.ilk</filename>
+ alongside compiling <filename>foo.obj</filename> file.
+ Specifying <filename>foo.ilk</filename> as a
+ side-effect of <filename>foo.obj</filename>
+ is <emphasis>not</emphasis> a recommended use of &SideEffect;,
+ because &SCons; handle side-effect files
+ slightly differently in its analysis of the dependency graph.
+ When a command produces multiple output files,
+ they should be specified as multiple targets of
+ the call to the relevant builder function,
+ and the &SideEffect; function itself should really only be used
+ when it's important to ensure that commands are not executed in parallel,
+ such as when a "peripheral" file (such as a log file)
+ may actually updated by more than one command invocation.
+
+ </para>
--- /dev/null
+<!--
+
+ __COPYRIGHT__
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+ <!--
+
+ <para>
+
+ If &SCons; is unaware that a build step produces an extra file,
+ the &SideEffect; method can be used to identify it,
+ so that the file can be used as a dependency in subsequent build steps.
+ However, the primary use for the &SideEffect; method
+ is to prevent two build steps from simultaneously modifying the same file.
+
+ </para>
+
+ TODO: currently doesn't work due to issue #2154:
+ http://scons.tigris.org/issues/show_bug.cgi?id=2154
+
+ <para>
+
+ If more than one build step creates or manipulates the same file,
+ it can cause unpleasant results if both build steps are run at the same time.
+ The shared file is declared as a side-effect of building the primary targets
+ and &SCons; will prevent the two build steps from running in parallel.
+
+ </para>
+
+ <para>
+
+ In this example, the <filename>SConscript</filename> uses
+ &SideEffect; to inform &SCons; about the additional output file.
+
+ </para>
+
+ <scons_example name="SideEffectSimple">
+ <file name="SConstruct" printme="1">
+ env = Environment()
+ f2 = env.Command('file2', 'log', Copy('$TARGET', '$SOURCE'))
+ f1 = env.Command('file1', [],
+ 'echo >$TARGET data1; echo >log updated file1'))
+ env.SideEffect('log', env.Command('file1', [],
+ 'echo >$TARGET data1; echo >log updated file1'))
+ </file>
+ </scons_example>
+
+ <para>
+
+ Even when run in parallel mode, &SCons; will run the two steps in order:
+
+ </para>
+
+ <scons_output example="SideEffectSimple">
+ <scons_output_command>scons -Q --jobs=2</scons_output_command>
+ </scons_output>
+
+ -->
+
+ <para>
+
+ Sometimes a program the you need to call
+ to build a target file
+ will also update another file,
+ such as a log file describing what the program
+ does while building the target.
+ For example, we the folowing configuration
+ would have &SCons; invoke a hypothetical
+ script named <application>build</application>
+ (in the local directory)
+ with command-line arguments that write
+ log information to a common
+ <filename>logfile.txt</filename> file:
+
+ </para>
+
+ <screen>
+ env = Environment()
+ env.Command('file1.out', 'file.in',
+ './build --log logfile.txt $SOURCE $TARGET')
+ env.Command('file2.out', 'file.in',
+ './build --log logfile.txt $SOURCE $TARGET')
+ <screen>
+
+ <para>
+
+ This can cause problems when running
+ the build in parallel if
+ &SCons; decides to update both targets
+ by running both program invocations at the same time.
+ The multiple program invocations
+ may interfere with each other
+ writing to the common log file,
+ leading at best to intermixed output in the log file,
+ and at worst to an actual failed build
+ (on a system like Windows, for example,
+ where only one process at a time can open the log file for writing).
+
+ </para>
+
+ <para>
+
+ We can make sure that &SCons; does not
+ run these <application>build</application>
+ commands at the same time
+ by using the &SideEffect; function
+ to specify that updating
+ the <filename>logfile.txt</filename> file
+ is a side effect of building the specified
+ <filename>file1</filename>
+ and
+ <filename>file2</filename>
+ target files:
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ f1 = env.Command('file1.out', 'file1.in',
+ './build --log logfile.txt $SOURCE $TARGET')
+ f2 = env.Command('file2.out', 'file2.in',
+ './build --log logfile.txt $SOURCE $TARGET')
+ env.SideEffect('logfile.txt', f1 + f2)
+ </programlisting>
+
+ <para>
+
+ </para>
+
+ <para>
+
+ This makes sure the the two
+ <application>./build</application> steps are run sequentially,
+ even withthe <filename>--jobs=2</filename> in the command line:
+
+ </para>
+
+ <screen>
+ % <userinput>scons -Q --jobs=2</userinput>
+ ./build --log logfile.txt file1.in file1.out
+ ./build --log logfile.txt file2.in file2.out
+ </screen>
+
+ <para>
+
+ The &SideEffect; function can be called multiple
+ times for the same side-effect file.
+ Additionally, the name used as a &SideEffect; does not
+ even need to actually exist as a file on disk.
+ &SCons; will still make sure
+ that the relevant targets
+ will be executed sequentially, not in parallel:
+
+ </para>
+
+ <programlisting>
+ env = Environment()
+ f1 = env.Command('file1.out', [], 'echo >$TARGET data1')
+ env.SideEffect('not_really_updated', f1)
+ f2 = env.Command('file2.out', [], 'echo >$TARGET data2')
+ env.SideEffect('not_really_updated', f2)
+ </programlisting>
+
+ <screen>
+ % <userinput>scons -Q --jobs=2</userinput>
+ echo > file1.out data1
+ echo > file2.out data2
+ </screen>
+
+ <para>
+
+ Note that it might be tempting to
+ use &SideEffect; for additional target files
+ that a command produces.
+ For example, versions the Microsoft Visual C/C++ compiler
+ produce a <filename>foo.ilk</filename>
+ alongside compiling <filename>foo.obj</filename> file.
+ Specifying <filename>foo.ilk</filename> as a
+ side-effect of <filename>foo.obj</filename>
+ is <emphasis>not</emphasis> a recommended use of &SideEffect;,
+ because &SCons; handle side-effect files
+ slightly differently in its analysis of the dependency graph.
+ When a command produces multiple output files,
+ they should be specified as multiple targets of
+ the call to the relevant builder function,
+ and the &SideEffect; function itself should really only be used
+ when it's important to ensure that commands are not executed in parallel,
+ such as when a "peripheral" file (such as a log file)
+ may actually updated by more than one command invocation.
+
+ </para>
'PROGSUFFIX': '.exe',
'PSPAWN': <function piped_spawn at 0x700000>,
'RC': 'rc',
- 'RCCOM': '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES',
+ 'RCCOM': <SCons.Action.FunctionAction instance at 0x700000>,
'RCFLAGS': [],
'RDirs': <SCons.Defaults.Variable_Method_Caller instance at 0x700000>,
'SCANNERS': [],
+RELEASE XXX - XXX
+
+From Luca Falavigna:
+
+ - Fix SCons man page indentation under Debian's man page macros.
+
+From Steven Knight:
+
+ - Clarify the man page description of the SConscript(src_dir) argument.
+
+ - User's Guide updates:
+
+ - Document the BUILD_TARGETS, COMMAND_LINE_TARGETS and
+ DEFAULT_TARGETS variables.
+
+ - Document the AddOption(), GetOption() and SetOption() functions.
+
+ - Document the Requires() function; convert to the Variables
+ object, its UnknownOptions() method, and its associated
+ BoolVariable(), EnumVariable(), ListVariable(), PackageVariable()
+ and PathVariable() functions.
+
+ - Document the Progress() function.
+
+ - Reorganize the chapter and sections describing the different
+ types of environments and how they interact. Document the
+ SetDefault() method. Document the PrependENVPath() and
+ AppendENVPath() functions.
+
+ - Reorganize the command-line arguments chapter. Document the
+ ARGLIST variable.
+
+ - Collect some miscellaneous sections into a chapter about
+ configuring build output.
+
+ - Man page updates:
+
+ - Document suggested use of the Visual C/C++ /FC option to fix
+ the ability to double-click on file names in compilation error
+ messages.
+
+ - Document the need to use Clean() for any SideEffect() files that
+ must be explicitly removed when their targets are removed.
+
+ - Explicitly document use of Node lists as input to Dependency().
+
+From Greg Noel:
+
+ - Document MergeFlags(), ParseConfig(), ParseFlags() and SideEffect()
+ in the User's Guide.
+
+From Gary Oberbrunner:
+
+ - Document use of the GetBuildFailures() function in the User's Guide.
+
+From Adam Simpkins:
+
+ - Add man page text clarifying the behavior of AddPreAction() and
+ AddPostAction() when called with multiple targets.
+
+From Alexey Zezukin:
+
+ - Fix incorrectly swapped man page descriptions of the --warn= options
+ for duplicate-environment and missing-sconscript.
+
+
+
RELEASE 0.98.5 - Sat, 07 Jun 2008 08:20:35 -0700
From Benoit Belley:
apply(_ActionAction.__init__, (self,)+args, kw)
self.varlist = kw.get('varlist', [])
+ if SCons.Util.is_String(self.varlist):
+ # prevent varlist="FOO" from being interpreted as ['F', 'O', 'O']
+ self.varlist=[self.varlist]
self.cmdstr = cmdstr
def function_name(self):
c = a.get_contents(target=[], source=[], env=Environment(XYZ = 'foo'))
assert c in matches_foo, repr(c)
+ # Make sure a bare string varlist works
+ a = SCons.Action.FunctionAction(GlobalFunc, varlist='XYZ')
+
+ matches_foo = map(lambda x: x + "foo", func_matches)
+
+ c = a.get_contents(target=[], source=[], env=Environment())
+ assert c in func_matches, repr(c)
+ c = a.get_contents(target=[], source=[], env=Environment(XYZ = 'foo'))
+ assert c in matches_foo, repr(c)
+
class Foo:
def get_contents(self, target, source, env):
return 'xyzzy'
switch by overriding the default &cv-link-CCPDBFLAGS; variable as follows:
<example>
-import SCons.Util
-env['CCPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Zi /Fd%s" % File(PDB)) or ""}'])
+env['CCPDBFLAGS'] = ['${(PDB and "/Zi /Fd%s" % File(PDB)) or ""}']
</example>
An alternative would be to use the <option>/Zi</option>
&b-MSVSSolution;
Builder (see below).
-It takes several lists of filenames to be placed into the project
-file.
+The &b-MSVSProject; builder
+takes several lists of filenames
+to be placed into the project file.
These are currently limited to
<literal>srcs</literal>,
<literal>incs</literal>,
<literal>buildtarget</literal>
value.
+Note that because &SCons; always executes its build commands
+from the directory in which the &SConstruct; file is located,
+if you generate a project file in a different directory
+than the &SConstruct; directory,
+users will not be able to double-click
+on the file name in compilation error messages
+displayed in the Visual Studio console output window.
+This can be remedied by adding the
+Visual C/C++
+.B /FC
+compiler option to the &cv-link-CCFLAGS; variable
+so that the compiler will print
+the full path name of any
+files that cause compilation errors.
+
Example usage:
<example>
import os
import sys
-import TestCmd
import TestSCons
test = TestSCons.TestSCons()
-if sys.platform != 'win32':
- msg = "Skipping Visual Studio test on non-Windows platform '%s'\n" % sys.platform
- test.skip_test(msg)
+# Make the test infrastructure think we have this version of MSVS installed.
+test._msvs_versions = ['6.0']
SConscript_contents = """\
-env=Environment(tools=['msvs'], MSVS_VERSION = '6.0')
+env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='6.0')
testsrc = ['test.c']
testincs = ['sdk.h']
test.subdir('work3')
test.write(['work3', 'SConstruct'], """\
-env=Environment(tools=['msvs'], MSVS_VERSION = '6.0')
+env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='6.0')
testsrc = ['test.c']
testincs = ['sdk.h']
import os.path
import sys
-import TestCmd
import TestSCons
test = TestSCons.TestSCons()
-if sys.platform != 'win32':
- msg = "Skipping Visual Studio test on non-Windows platform '%s'\n" % sys.platform
- test.skip_test(msg)
+# Make the test infrastructure think we have this version of MSVS installed.
+test._msvs_versions = ['7.0']
+
+
expected_slnfile = """\
Microsoft Visual Studio Solution File, Format Version 7.00
SConscript_contents = """\
-env=Environment(tools=['msvs'], MSVS_VERSION = '7.0')
+env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='7.0')
testsrc = ['test1.cpp', 'test2.cpp']
testincs = ['sdk.h']
test.run(chdir='work2', arguments=".")
vcproj = test.read(['work2', 'src', 'Test.vcproj'], 'r')
-expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work2', 'SConstruct')
+expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work2', 'SConstruct',
+ python=python)
# don't compare the pickled data
assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
test.subdir('work3')
test.write(['work3', 'SConstruct'], """\
-env=Environment(tools=['msvs'], MSVS_VERSION = '7.0')
+env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='7.0')
testsrc = ['test1.cpp', 'test2.cpp']
testincs = ['sdk.h']
test.must_exist(test.workpath('work3', 'Test.vcproj'))
vcproj = test.read(['work3', 'Test.vcproj'], 'r')
-expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work3', 'SConstruct')
+expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work3', 'SConstruct',
+ python=python)
# don't compare the pickled data
assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
import os.path
import sys
-import TestCmd
import TestSCons
test = TestSCons.TestSCons()
-if sys.platform != 'win32':
- msg = "Skipping Visual Studio test on non-Windows platform '%s'\n" % sys.platform
- test.skip_test(msg)
+# Make the test infrastructure think we have this version of MSVS installed.
+test._msvs_versions = ['7.1']
+
+
expected_slnfile = """\
Microsoft Visual Studio Solution File, Format Version 8.00
SConscript_contents = """\
-env=Environment(tools=['msvs'], MSVS_VERSION = '7.1')
+env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='7.1')
testsrc = ['test1.cpp', 'test2.cpp']
testincs = ['sdk.h']
test.run(chdir='work2', arguments=".")
vcproj = test.read(['work2', 'src', 'Test.vcproj'], 'r')
-expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work2', 'SConstruct')
+expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work2', 'SConstruct',
+ python=python)
# don't compare the pickled data
assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
test.subdir('work3')
test.write(['work3', 'SConstruct'], """\
-env=Environment(tools=['msvs'], MSVS_VERSION = '7.1')
+env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='7.1')
testsrc = ['test1.cpp', 'test2.cpp']
testincs = ['sdk.h']
test.must_exist(test.workpath('work3', 'Test.vcproj'))
vcproj = test.read(['work3', 'Test.vcproj'], 'r')
-expect = test.msvs_substitute(expected_vcprojfile, '7.1', 'work3', 'SConstruct')
+expect = test.msvs_substitute(expected_vcprojfile, '7.1', 'work3', 'SConstruct',
+ python=python)
# don't compare the pickled data
assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
import os.path
import sys
-import TestCmd
import TestSCons
test = TestSCons.TestSCons()
-if sys.platform != 'win32':
- msg = "Skipping Visual Studio test on non-Windows platform '%s'\n" % sys.platform
- test.skip_test(msg)
+# Make the test infrastructure think we have this version of MSVS installed.
+test._msvs_versions = ['8.0']
+
+
expected_slnfile = """\
Microsoft Visual Studio Solution File, Format Version 9.00
SConscript_contents = """\
-env=Environment(tools=['msvs'], MSVS_VERSION = '8.0')
+env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='8.0')
testsrc = ['test1.cpp', 'test2.cpp']
testincs = ['sdk.h']
vcproj = test.read(['work2', 'src', 'Test.vcproj'], 'r')
expect = test.msvs_substitute(expected_vcprojfile,
- '7.0',
+ '8.0',
'work2',
'SConstruct',
- project_guid="{25F6CE89-8E22-2910-8B6E-FFE6DC1E2792}")
+ project_guid="{FC63FE9E-71B3-06CC-11AF-2077D8108DFE}",
+ python=python)
# don't compare the pickled data
assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
test.must_exist(test.workpath('work2', 'src', 'Test.sln'))
sln = test.read(['work2', 'src', 'Test.sln'], 'r')
-expect = test.msvs_substitute(expected_slnfile, '7.0',
+expect = test.msvs_substitute(expected_slnfile, '8.0',
os.path.join('work2', 'src'))
# don't compare the pickled data
assert sln[:len(expect)] == expect, test.diff_substr(expect, sln)
test.subdir('work3')
test.write(['work3', 'SConstruct'], """\
-env=Environment(tools=['msvs'], MSVS_VERSION = '8.0')
+env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='8.0')
testsrc = ['test1.cpp', 'test2.cpp']
testincs = ['sdk.h']
test.must_exist(test.workpath('work3', 'Test.vcproj'))
vcproj = test.read(['work3', 'Test.vcproj'], 'r')
-expect = test.msvs_substitute(expected_vcprojfile, '8.0', 'work3', 'SConstruct')
+expect = test.msvs_substitute(expected_vcprojfile, '8.0', 'work3', 'SConstruct',
+ python=python)
# don't compare the pickled data
assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
--- /dev/null
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test explicit checkouts from local RCS files.
+"""
+
+import os.path
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+rcs = test.where_is('rcs')
+if not rcs:
+ test.skip_test("Could not find 'rcs'; skipping test(s).\n")
+
+ci = test.where_is('ci')
+if not ci:
+ test.skip_test("Could not find `ci' command, skipping test(s).\n")
+
+co = test.where_is('co')
+if not co:
+ test.skip_test("Could not find `co' command, skipping test(s).\n")
+
+
+
+main_cpp_contents = """\
+#include <stdio.h>
+#include <stdlib.h>
+int
+main(int argc, char *argv[])
+{
+ printf("main.c %s\\n");
+ exit (0);
+}
+"""
+
+test.write('main.c', main_cpp_contents % 1)
+
+test.run(program = ci, arguments = '-f -tmain.c main.c', stderr = None)
+
+
+
+test.write('SConstruct', """
+import os
+for key in ['LOGNAME', 'USERNAME', 'USER']:
+ logname = os.environ.get(key)
+ if logname: break
+ENV = {'PATH' : os.environ['PATH'],
+ 'LOGNAME' : logname}
+env = Environment(ENV=ENV, RCS_COFLAGS='-q')
+env.SourceCode('main.c', env.RCS())
+env2 = env.Clone()
+env2.Program('main.exe', 'main.c')
+""")
+
+test.run()
+
+test.run(program = test.workpath('main.exe'), stdout = "main.c 1\n")
+
+
+
+test.run(program = co, arguments = '-l main.c', stderr = None)
+
+test.write('main.c', main_cpp_contents % 2)
+
+test.not_up_to_date(arguments = 'main.exe')
+
+test.run(program = test.workpath('main.exe'), stdout = "main.c 2\n")
+
+
+
+test.pass_test()