# Controlling a Build From the Command Line

&SCons; provides a number of ways for you as the writer of the &SConscript; files to give you (and your users) the ability to control the build execution. The arguments that can be specified on the command line are broken down into three types:

Options

  Command-line options always begin with one or two `-` (hyphen) characters. &SCons; provides ways for you to examine and set options values from within your &SConscript; files, as well as the ability to define your own custom options. See , below.

Variables

  Any command-line argument containing an `=` (equal sign) is considered a variable setting with the form `variable`=value. &SCons; provides direct access to all of the command-line variable settings, the ability to apply command-line variable settings to &consenvs;, and functions for configuring specific types of variables (Boolean values, path names, etc.) with automatic validation of the specified values. See , below.

Targets

  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 you are telling &SCons; 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 , below.

## Command-Line Options

&SCons; has many command-line options that control its behavior. An &SCons; command-line option always begins with one or two hyphen (`-`) characters.

### Not Having to Specify Command-Line Options Each Time: the &SCONSFLAGS; Environment Variable

You may find yourself using the same command-line options every time you run &SCons;. For example, you might find it saves time to specify `-j 2` to have &SCons; run up to two build commands in parallel. To avoid having to type `-j 2` by hand every time, you can set the external environment variable &SCONSFLAGS; to a string containing `-j 2`, as well as any other command-line options that you want &SCons; to always use. &SCONSFLAGS; is an exception to the usual rule that &SCons; itself avoids looking at environment variables from the shell you are running.

If, for example, you are using a POSIX shell such as `bash` or `zsh` and you always want &SCons; to use the `-Q` option, you can set the &SCONSFLAGS; environment as follows:

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')
foo.in
scons
export SCONSFLAGS="-Q"
scons

For &csh;-style shells on POSIX systems you can set the &SCONSFLAGS; environment variable as follows:

    $ setenv SCONSFLAGS "-Q"

For the Windows command shell (`cmd`) you can set the &SCONSFLAGS; environment variable as follows:

    C:\Users\foo> set SCONSFLAGS="-Q"

To set &SCONSFLAGS; more permanently you can add the setting to the shell's startup file on POSIX systems, and on Windows you can use the `System Properties` control panel applet to select `Environment Variables` and set it there.

### Getting Values Set by Command-Line Options: the &GetOption; Function

&SCons; provides the &f-link-GetOption; function to get the values set by the various command-line options.

One use case for &GetOption; is to check whether or not the `-h` or `--help` 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. If you know that your configuration does not define any additional help text in subsidiary SConscript files, you can speed up displaying the command-line help by using the &GetOption; function to load the subsidiary SConscript files only if the `-h` or `--help` option has not been specified like this:

if not GetOption('help'): SConscript('src/SConscript', export='env')

In general, the string that you pass to the &f-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 &f-GetOption; strings for fetching them, are available in the section, below.

&f-GetOption; can be used to retrieve the values of options defined by calls to &f-link-AddOption;. A &f-GetOption; call must appear after the &f-AddOption; call for that option. If the &f-AddOption; call supplied a `dest` keyword argument, a string with that name is what to pass as the argument to &f-GetOption;, otherwise it is a (possibly modified) version of the first long option name - see &f-link-AddOption;.

### Setting Values of Command-Line Options: the &SetOption; Function

You can also set the values of &SCons; command-line options from within the &SConscript; files by using the &f-link-SetOption; function. The strings that you use to set the values of &SCons; command-line options are available in the section, below.

One use of the &SetOption; function is to specify a value for the `-j` or `--jobs` option, so that you 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 `-j` option is somewhat system-dependent. One rough guideline is that the more processors your system has, the higher you want to set the `-j` value, in order to take advantage of the number of CPUs.

For example, suppose the administrators of your development systems have standardized on setting a `NUM_CPU` 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 provides the right level of flexibility:

import os

num_cpu = int(os.environ.get('NUM_CPU', 2)) SetOption('num_jobs', num_cpu) print("running with -j %s" % GetOption('num_jobs'))
foo.in

The above snippet of code sets the value of the `--jobs` option to the value specified in the `NUM_CPU` 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 `--jobs` value is `num_jobs` for historical reasons.) The code in this example prints the `num_jobs` value for illustrative purposes. It uses a default value of `2` to provide some minimal parallelism even on single-processor systems:

scons -Q

But if the `NUM_CPU` environment variable is set, then use that for the default number of jobs:

export NUM_CPU="4"
scons -Q

But any explicit `-j` or `--jobs` value you specify on the command line is used first, regardless of whether or not the `NUM_CPU` environment variable is set:

scons -Q -j 7
export NUM_CPU="4"
scons -Q -j 3

### Strings for Getting or Setting Values of &SCons; Command-Line Options

The strings that you can pass to the &f-link-GetOption; and &f-link-SetOption; functions usually correspond to the first long-form option name (that is, name beginning with two hyphen characters: `--`), after replacing any remaining hyphen characters with underscores.

&SetOption; is not currently supported for options added with &AddOption;.

The full list of strings and the variables they correspond to is as follows:

String for &GetOption; and &SetOption; | Command-Line Option(s)
--- | ---
`cache_debug` | `--cache-debug`
`cache_disable` | `--cache-disable`
`cache_force` | `--cache-force`
`cache_show` | `--cache-show`
`clean` | `-c`, `--clean`, `--remove`
`config` | `--config`
`directory` | `-C`, `--directory`
`diskcheck` | `--diskcheck`
`duplicate` | `--duplicate`
`file` | `-f`, `--file`, `--makefile` , `--sconstruct`
`help` | `-h`, `--help`
`ignore_errors` | `--ignore-errors`
`implicit_cache` | `--implicit-cache`
`implicit_deps_changed` | `--implicit-deps-changed`
`implicit_deps_unchanged` | `--implicit-deps-unchanged`
`interactive` | `--interact`, `--interactive`
`keep_going` | `-k`, `--keep-going`
`max_drift` | `--max-drift`
`no_exec` | `-n`, `--no-exec`, `--just-print`, `--dry-run`, `--recon`
`no_site_dir` | `--no-site-dir`
`num_jobs` | `-j`, `--jobs`
`profile_file` | `--profile`
`question` | `-q`, `--question`
`random` | `--random`
`repository` | `-Y`, `--repository`, `--srcdir`
`silent` | `-s`, `--silent`, `--quiet`
`site_dir` | `--site-dir`
`stack_size` | `--stack-size`
`taskmastertrace_file` | `--taskmastertrace`
`warn` | `--warn` `--warning`

### Adding Custom Command-Line Options: the &AddOption; Function

&SCons; also allows you to define your own command-line options with the &f-link-AddOption; function. The &AddOption; function takes the same arguments as the `add_option` method from the standard Python library module optparse. The &AddOption; function is, in fact, implemented using a subclass of `optparse.OptionParser`.

Once you add a custom command-line option with the &AddOption; function, the value of the option (if any) is immediately available using the standard &f-link-GetOption; function. The argument to &f-GetOption; must be the name of the variable which holds the option. If the `dest` keyword argument to &AddOption; is specified, the value is the variable name. given. If not given, it is the name (without the leading hyphens) of the first long option name given to &AddOption; after replacing any remaining hyphen characters with underscores, since hyphens are not legal in Python identifier names.

&SetOption; is not currently supported for options added with &AddOption;.

One useful example of using this functionality is to provide a `--prefix` to help describe where to install files:

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)
foo.in

The above code uses the &GetOption; function to set the `$PREFIX` &consvar; to a value you specify with a command-line option of `--prefix`. Because `$PREFIX` expands to a null string if it's not initialized, running &SCons; without the option of `--prefix` installs the file in the `/usr/bin/` directory:

scons -Q -n

But specifying `--prefix=/tmp/install` on the command line causes the file to be installed in the `/tmp/install/usr/bin/` directory:

scons -Q -n --prefix=/tmp/install

Option-arguments separated from long options by whitespace, rather than by an `=`, cannot be correctly resolved by &SCons;. While `--input=ARG` is clearly opt followed by arg, for `--input ARG` it is not possible to tell without instructions whether `ARG` is an argument belonging to the `input` option or a positional argument. &SCons; treats positional arguments as either command-line build options or command-line targets which are made available for use in an &SConscript; (see the immediately following sections for details). Thus, they must be collected before &SConscript; processing takes place. Since &AddOption; calls, which provide the processing instructions to resolve any ambiguity, happen in an &SConscript;, &SCons; does not know in time for options added this way, and unexpected things happen, such as option-arguments assigned as targets and/or exceptions due to missing option-arguments.

As a result, this usage style should be avoided when invoking &scons;. For single-argument options, use the `--input=ARG` form on the command line. For multiple-argument options (`nargs` greater than one), set `nargs` to one in &AddOption; calls and either: combine the option-arguments into one word with a separator, and parse the result in your own code (see the built-in `--debug` option, which allows specifying multiple arguments as a single comma-separated word, for an example of such usage); or allow the option to be specified multiple times by setting `action='append'`. Both methods can be supported at the same time.

## Command-Line `variable`=value Build Variables

You may want to control various aspects of your build by allowing `variable`=value values to be specified on the command line. For example, suppose you want to be able to build a debug version of a program by running &SCons; as follows:

    % scons -Q debug=1

&SCons; provides an &ARGUMENTS; dictionary that stores all of the `variable`=value assignments from the command line. This allows you to modify aspects of your build in response to specifications on the command line. (Note that unless you want to require a variable always be specified you probably want to use the Python dictionary `get` method, which allows you to designate a default value to be used if there is no specification on the command line.)

The following code sets the &cv-link-CCFLAGS; &consvar; in response to the `debug` flag being set in the &ARGUMENTS; dictionary:

env = Environment() debug = ARGUMENTS.get('debug', 0) if int(debug): env.Append(CCFLAGS='-g') env.Program('prog.c')
prog.c

This results in the `-g` compiler option being used when `debug=1` is used on the command line:

scons -Q debug=0
scons -Q debug=0
scons -Q debug=1
scons -Q debug=1

&SCons; keeps track of the precise command line used to build each object file, and as a result can determine that the object and executable files need rebuilding when the value of the `debug` argument has changed.

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 less than ideal if you want to allow specifying 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.

To accomodate these requirements, &SCons; provides an &ARGLIST; variable that gives you direct access to `variable`=value 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 lets you add to the &CPPDEFINES; &consvar; by specifying multiple `define=` settings on the command line:

cppdefines = [] for key, value in ARGLIST: if key == 'define': cppdefines.append(value) env = Environment(CPPDEFINES=cppdefines) env.Object('prog.c')
prog.c

Yields the following output:

scons -Q define=FOO
scons -Q define=FOO define=BAR

Note that the &ARGLIST; and &ARGUMENTS; variables do not interfere with each other, but rather provide slightly different views into how you specified `variable`=value 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 &Python; dictionary access), and the &ARGLIST; list is more flexible (since you can examine the specific order in which the command-line variable settings were given).

### Controlling Command-Line Build Variables

Being able to use a command-line build variable like `debug=1` 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 &consvar;. To help with this, &SCons; provides a &Variables; class to define such build variables easily, and a mechanism to apply the build variables to a &consenv;. This allows you to control how the build variables affect &consenvs;.

For example, suppose that you want to set a &RELEASE; &consvar; 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 define 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; &consvar;:

vars = Variables(None, ARGUMENTS) vars.Add('RELEASE', default=0) env = Environment(variables=vars, CPPDEFINES={'RELEASE_BUILD': '${RELEASE}'}) env.Program(['foo.c', 'bar.c'])
foo.c
bar.c

This &SConstruct; file first creates a &Variables; object which uses the values from the command-line options dictionary &ARGUMENTS; (the `vars=Variables(None, ARGUMENTS)` call). It then uses the object's &Add; method to indicate that the &RELEASE; variable can be set on the command line, and that if not set the default value is `0`. The newly created &Variables; object is passed to the &Environment; call used to create the &consenv; using a &variables; keyword argument. This then allows you 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:

scons -Q RELEASE=1

Historical note: In old &SCons; (prior to 0.98.1), these build variables were known as "command-line build options." At that time, class was named &Options; and the predefined functions to construct options were named &BoolOption;, &EnumOption;, &ListOption;, &PathOption;, &PackageOption; and &AddOptions; (contrast with the current names in , below). You may encounter these names in older &SConscript; files, wiki pages, blog entries, StackExchange articles, etc. These old names no longer work, but a mental substitution of Variable for Option allows the concepts to transfer to current usage models.

### Providing Help for Command-Line Build Variables

To make command-line build variables most useful, you ideally want to provide some help text to describe the available variables when the you ask for help (run `scons -h`). You can write this text by hand, but &SCons; provides some assistance. Variables objects provide a &GenerateHelpText; method the generate text that describes the various variables that have been added to it. The default text includes the help string itself plus other information such as allowed values. (The generated text can also be customized by replacing the `FormatVariableHelpText` method). You then pass the output from this method to the &Help; function:

vars = Variables(None, ARGUMENTS) vars.Add('RELEASE', help='Set to 1 to build for release', default=0) env = Environment(variables=vars) Help(vars.GenerateHelpText(env))

&SCons; now displays some useful text when the `-h` option is used:

scons -Q -h

You can see the help output shows the default value as well as the current actual value of the build variable.

### Reading Build Variables From a File

Being able to to specify the value of a build variable on the command line is useful, but can still become tedious if you have to specify the variable every time you run &SCons;. To make this easier, you can provide customized build variable settings in a local file by providing a file name when the &Variables; object is created:

vars = Variables('custom.py') vars.Add('RELEASE', help='Set to 1 to build for release', default=0) env = Environment(variables=vars, CPPDEFINES={'RELEASE_BUILD': '${RELEASE}'}) env.Program(['foo.c', 'bar.c']) Help(vars.GenerateHelpText(env))
foo.c
bar.c
RELEASE = 1

This then allows you to control the &RELEASE; variable by setting it in the &custom_py; file:

Note that this file is actually executed like a Python script. Now when you run &SCons;:

scons -Q

And if you change the contents of &custom_py; to:

vars = Variables('custom.py') vars.Add('RELEASE', help='Set to 1 to build for release', default=0) env = Environment(variables=vars, CPPDEFINES={'RELEASE_BUILD': '${RELEASE}'}) env.Program(['foo.c', 'bar.c']) Help(vars.GenerateHelpText(env))
foo.c
bar.c
RELEASE = 0

The object files are rebuilt appropriately with the new variable:

scons -Q

Finally, you can combine both methods with:

    vars = Variables('custom.py', ARGUMENTS)

where values in the option file &custom_py; get overwritten by the ones specified on the command line.

### Pre-Defined Build Variable Functions

&SCons; provides a number of convenience functions that provide ready-made behaviors for various types of command-line build variables. These functions all return a tuple which is ready to be passed to the &Add; or &AddVariables; method call. You are of course free to define your own behaviors as well.

#### True/False Values: the &BoolVariable; Build Variable Function

It is 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 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;.

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:

vars = Variables('custom.py') vars.Add(BoolVariable('RELEASE', help='Set to build for release', default=0)) env = Environment(variables=vars, CPPDEFINES={'RELEASE_BUILD': '${RELEASE}'}) env.Program('foo.c')
foo.c

With this build variable in place, the &RELEASE; variable can now be enabled by setting it to the value `yes` or `t`:

scons -Q RELEASE=yes foo.o
scons -Q RELEASE=t foo.o

Other values that equate to &true; include `y`, `1`, `on` and `all`.

Conversely, &RELEASE; may now be given a &false; value by setting it to `no` or `f`:

scons -Q RELEASE=no foo.o
scons -Q RELEASE=f foo.o

Other values that equate to &false; include `n`, `0`, `off` and `none`.

Lastly, if you try to specify any other value, &SCons; supplies an appropriate error message:

scons -Q RELEASE=bad_value foo.o

#### Single Value From a Selection: the &EnumVariable; Build Variable Function

Suppose that you want to allow setting a &COLOR; variable that selects a background color to be displayed by an application, but that you want to restrict the choices to a specific set of allowed colors. You can set this up quite easily using the &EnumVariable; function, which takes a list of &allowed_values; in addition to the variable name, default value, and help text arguments:

vars = Variables('custom.py') vars.Add( EnumVariable( 'COLOR', help='Set background color', default='red', allowed_values=('red', 'green', 'blue'), ) ) env = Environment(variables=vars, CPPDEFINES={'COLOR': '"${COLOR}"'}) env.Program('foo.c') Help(vars.GenerateHelpText(env))
foo.c

You can now explicitly set the &COLOR; build variable to any of the specified allowed values:

scons -Q COLOR=red foo.o
scons -Q COLOR=blue foo.o
scons -Q COLOR=green foo.o

But, importantly, an attempt to set &COLOR; to a value that's not in the list generates an error message:

scons -Q COLOR=magenta foo.o

This example can also serve to further illustrate help generation: the help message here picks up not only the `help` text, but augments it with information gathered from `allowed_values` and `default`:

scons -Q -h

The &EnumVariable; function also provides a way to map alternate names to allowed values. Suppose, for example, you want to allow the word `navy` to be used as a synonym for `blue`. You do this by adding a &map; dictionary that maps its key values to the desired allowed value:

vars = Variables('custom.py') vars.Add( EnumVariable( 'COLOR', help='Set background color', default='red', allowed_values=('red', 'green', 'blue'), map={'navy': 'blue'}, ) ) env = Environment(variables=vars, CPPDEFINES={'COLOR': '"${COLOR}"'}) env.Program('foo.c')
foo.c

Now you can supply `navy` on the command line, and &SCons; translates that into `blue` when it comes time to use the &COLOR; variable to build a target:

scons -Q COLOR=navy foo.o

By default, when using the &EnumVariable; function, the allowed values are case-sensitive:

scons -Q COLOR=Red foo.o
scons -Q COLOR=BLUE foo.o
scons -Q COLOR=nAvY foo.o

The &EnumVariable; function can take an additional &ignorecase; keyword argument that, when set to `1`, tells &SCons; to allow case differences when the values are specified:

vars = Variables('custom.py') vars.Add( EnumVariable( 'COLOR', help='Set background color', default='red', allowed_values=('red', 'green', 'blue'), map={'navy': 'blue'}, ignorecase=1, ) ) env = Environment(variables=vars, CPPDEFINES={'COLOR': '"${COLOR}"'}) env.Program('foo.c')
foo.c

Which yields the output:

scons -Q COLOR=Red foo.o
scons -Q COLOR=BLUE foo.o
scons -Q COLOR=nAvY foo.o
scons -Q COLOR=green foo.o

Notice that an &ignorecase; value of `1` preserves the case-spelling supplied, only ignoring the case for matching. If you want &SCons; to translate the names into lower-case, regardless of the case used by the user, specify an &ignorecase; value of `2`:

vars = Variables('custom.py') vars.Add( EnumVariable( 'COLOR', help='Set background color', default='red', allowed_values=('red', 'green', 'blue'), map={'navy': 'blue'}, ignorecase=2, ) ) env = Environment(variables=vars, CPPDEFINES={'COLOR': '"${COLOR}"'}) env.Program('foo.c')
foo.c

Now &SCons; uses values of `red`, `green` or `blue` regardless of how those values are spelled on the command line:

scons -Q COLOR=Red foo.o
scons -Q COLOR=nAvY foo.o
scons -Q COLOR=GREEN foo.o

#### Multiple Values From a List: the &ListVariable; Build Variable Function

Another way in which you might want to control a build variable is to specify a list of allowed values, of which one or more can be chosen (where &EnumVariable; allows exactly one value to be chosen). &SCons; provides this through the &ListVariable; function. If, for example, you want to be able to set a &COLORS; variable to one or more of the allowed values:

vars = Variables('custom.py') vars.Add( ListVariable( 'COLORS', help='List of colors', default=0, names=['red', 'green', 'blue'] ) ) env = Environment(variables=vars, CPPDEFINES={'COLORS': '"${COLORS}"'}) env.Program('foo.c')
foo.c

You can now specify a comma-separated list of allowed values, which get translated into a space-separated list for passing to the build commands:

scons -Q COLORS=red,blue foo.o
scons -Q COLORS=blue,green,red foo.o

In addition, the &ListVariable; function lets you specify explicit keywords of &all; or &none; to select all of the allowed values, or none of them, respectively:

scons -Q COLORS=all foo.o
scons -Q COLORS=none foo.o

And, of course, an illegal value still generates an error message:

scons -Q COLORS=magenta foo.o

You can use this last characteristic as a way to enforce at least one of your valid options being chosen by specifying the valid values with the `names` parameter and then giving a value not in that list as the `default` parameter - that way if no value is given on the command line, the default is chosen, &SCons; errors out as this is invalid. The example is, in fact, set up that way by using `0` as the default:

scons -Q foo.o

This technique works for &EnumVariable; as well.

#### Path Names: the &PathVariable; Build Variable Function

&SCons; provides 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 preprocessor macro that controls the location of a configuration file:

vars = Variables('custom.py') vars.Add( PathVariable( 'CONFIG', help='Path to configuration file', default='__ROOT__/etc/my_config' ) ) env = Environment(variables=vars, CPPDEFINES={'CONFIG_FILE': '"$CONFIG"'}) env.Program('foo.c')
foo.c
/opt/location
/opt/location

This allows you to override the &CONFIG; build variable on the command line as necessary:

scons -Q foo.o
scons -Q CONFIG=__ROOT__/usr/local/etc/other_config foo.o

By default, &PathVariable; checks to make sure that the specified path exists and generates an error if it doesn't:

scons -Q CONFIG=__ROOT__/does/not/exist foo.o

&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 as the validation function:

vars = Variables('custom.py') vars.Add( PathVariable( 'CONFIG', help='Path to configuration file', default='__ROOT__/etc/my_config', validator=PathVariable.PathIsFile, ) ) env = Environment(variables=vars, CPPDEFINES={'CONFIG_FILE': '"$CONFIG"'}) env.Program('foo.c')
foo.c
/opt/location

Conversely, to ensure that any specified paths are directories and not files, use the &PathVariable_PathIsDir; method as the validation function:

vars = Variables('custom.py') vars.Add( PathVariable( 'DBDIR', help='Path to database directory', default='__ROOT__/var/my_dbdir', validator=PathVariable.PathIsDir, ) ) env = Environment(variables=vars, CPPDEFINES={'DBDIR': '"$DBDIR"'}) env.Program('foo.c')
foo.c
/opt/location

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 as the validation function:

vars = Variables('custom.py') vars.Add( PathVariable( 'DBDIR', help='Path to database directory', default='__ROOT__/var/my_dbdir', validator=PathVariable.PathIsDirCreate, ) ) env = Environment(variables=vars, CPPDEFINES={'DBDIR': '"$DBDIR"'}) env.Program('foo.c')
foo.c
/opt/location

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 you supply:

vars = Variables('custom.py') vars.Add( PathVariable( 'OUTPUT', help='Path to output file or directory', default=None, validator=PathVariable.PathAccept, ) ) env = Environment(variables=vars, CPPDEFINES={'OUTPUT': '"$OUTPUT"'}) env.Program('foo.c')
foo.c

#### Enabled/Disabled Path Names: the &PackageVariable; Build Variable Function

Sometimes you want to give even more control over a path name variable, allowing them to be explicitly enabled or disabled by using `yes` or `no` keywords, in addition to allowing supplying an explicit path name. &SCons; provides the &PackageVariable; function to support this:

vars = Variables("custom.py") vars.Add( PackageVariable("PACKAGE", help="Location package", default="__ROOT__/opt/location") ) env = Environment(variables=vars, CPPDEFINES={"PACKAGE": '"$PACKAGE"'}) env.Program("foo.c")
foo.c
/opt/location
/opt/location

When the &SConscript; file uses the &PackageVariable; function, you can still use the default or supply an overriding path name, but you 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 -Q foo.o
scons -Q PACKAGE=__ROOT__/usr/local/location foo.o
scons -Q PACKAGE=yes foo.o
scons -Q PACKAGE=no foo.o

### Adding Multiple Command-Line Build Variables at Once

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 the build variables to be added to the object. Each build variable is specified as either a tuple of arguments, or as a call to one of the pre-defined functions for pre-packaged command-line build variables, which returns such a tuple. Note that an individual tuple cannot take keyword arguments in the way that a call to &Add; or one of the build variable functions can. The order of variables given to &AddVariables; does not matter.

vars = Variables() vars.AddVariables( ('RELEASE', 'Set to 1 to build for release', 0), ('CONFIG', 'Configuration file', '/etc/my_config'), BoolVariable('warnings', help='compilation with -Wall and similiar', default=1), EnumVariable( 'debug', help='debug output and symbols', default='no', allowed_values=('yes', 'no', 'full'), map={}, ignorecase=0, ), ListVariable( 'shared', help='libraries to build as shared libraries', default='all', names=list_of_libs, ), PackageVariable( 'x11', help='use X11 installed here (yes = search some places)', default='yes' ), PathVariable('qtdir', help='where the root of Qt is installed', default=qtdir), )

### Handling Unknown Command-Line Build Variables: the &UnknownVariables; Function

Humans, of course, occasionally misspell variable names in their command-line settings. &SCons; does not generate an error or warning for any unknown variables specified on the command line, because it can not reliably tell whether a given "misspelled" variable is really unknown and a potential problem or not. After all, you might be processing arguments directly using &ARGUMENTS; or &ARGLIST; with some Python code in your &SConscript; file.

If, however, you are using a &Variables; object to define a specific set of command-line build variables that you expect to be able to set, you may want to provide an error message or warning of your own if a variable setting is specified that is not 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 to get the settings &Variables; did not recognize:

vars = Variables(None) vars.Add('RELEASE', help='Set to 1 to build for release', default=0) env = Environment(variables=vars, CPPDEFINES={'RELEASE_BUILD': '${RELEASE}'}) unknown = vars.UnknownVariables() if unknown: print("Unknown variables: %s" % " ".join(unknown.keys())) Exit(1) env.Program('foo.c')
foo.c

The &UnknownVariables; method returns a dictionary containing the keywords and values of any variables specified on the command line that are not among the variables known to the &Variables; object (from having been specified using the &Variables; object's &Add; method). The example above, checks whether the dictionary returned by &UnknownVariables; is non-empty, and if so prints the Python list containing the names of the unknown variables and then calls the &Exit; function to terminate &SCons;:

scons -Q NOT_KNOWN=foo

Of course, you can process the items in the dictionary returned by the &UnknownVariables; function in any way appropriate to your build configuration, including just printing a warning message but not exiting, logging an error somewhere, etc.

Note that you must delay the call of &UnknownVariables; until after you have applied the &Variables; object to a &consenv; with the `variables=` keyword argument of an &Environment; call: the variables in the object are not fully processed until this has happened.

## Command-Line Targets

### Fetching Command-Line Targets: the &COMMAND_LINE_TARGETS; Variable

&SCons; provides a &COMMAND_LINE_TARGETS; variable that lets you fetch the list of targets that were 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 whenever a specific program is built. You can do this by checking for the target in the &COMMAND_LINE_TARGETS; list:

if 'bar' in COMMAND_LINE_TARGETS: print("Don't forget to copy `bar' to the archive!") Default(Program('foo.c')) Program('bar.c')
foo.c
foo.c

Now, running &SCons; with the default target works as usual, but explicity specifying the &bar; target on the command line generates the warning message:

scons -Q
scons -Q bar

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.

### Controlling the Default Targets: the &Default; Function

You can control which targets &SCons; builds by default - that is, when there are no targets specified on the command line. As mentioned previously, &SCons; normally builds every target in or below the current directory unless you explicitly specify one or more targets on the command line. Sometimes, however, you may want to specify that only certain programs, or programs in certain directories, should be built by default. You do this with the &Default; function:

env = Environment() hello = env.Program('hello.c') env.Program('goodbye.c') Default(hello)
hello.c
goodbye.c

This &SConstruct; file knows how to build two programs, &hello; and &goodbye;, but only builds the &hello; program by default:

scons -Q
scons -Q
scons -Q goodbye

Note that, even when you use the &Default; function in your &SConstruct; file, you can still explicitly specify the current directory (`.`) on the command line to tell &SCons; to build everything in (or below) the current directory:

scons -Q .

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:

env = Environment() prog1 = env.Program('prog1.c') Default(prog1) prog2 = env.Program('prog2.c') prog3 = env.Program('prog3.c') Default(prog3)
prog1.c
prog2.c
prog3.c

Or you can specify more than one target in a single call to the &Default; function:

    env = Environment()
    prog1 = env.Program('prog1.c')
    prog2 = env.Program('prog2.c')
    prog3 = env.Program('prog3.c')
    Default(prog1, prog3)

Either of these last two examples build only the prog1 and prog3 programs by default:

scons -Q
scons -Q .

You can list a directory as an argument to &Default;:

env = Environment() env.Program(['prog1/main.c', 'prog1/foo.c']) env.Program(['prog2/main.c', 'prog2/bar.c']) Default('prog1')
int main() { printf("prog1/main.c\n"); }
int foo() { printf("prog1/foo.c\n"); }
int main() { printf("prog2/main.c\n"); }
int bar() { printf("prog2/bar.c\n"); }

In which case only the target(s) in that directory are built by default:

scons -Q
scons -Q
scons -Q .

Lastly, if for some reason you don't want any targets built by default, you can use the Python `None` variable:

env = Environment() prog1 = env.Program('prog1.c') prog2 = env.Program('prog2.c') Default(None)
prog1.c
prog2.c

Which would produce build output like:

scons -Q
scons -Q .

#### Fetching the List of Default Targets: the &DEFAULT_TARGETS; Variable

&SCons; provides a &DEFAULT_TARGETS; variable that lets you get at the current list of default targets specified by calls to the &Default; function or method. 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. You can do this easily by calling the `str` on the elements in a list comprehension:

prog1 = Program('prog1.c') Default(prog1) print("DEFAULT_TARGETS is %s" % [str(t) for t in DEFAULT_TARGETS])
prog1.c

(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 you leave off the `-Q` flag when you run &SCons;:)

scons

Second, the contents of the &DEFAULT_TARGETS; list changes in response to calls to the &Default; function, as you can see from the following &SConstruct; file:

prog1 = Program('prog1.c') Default(prog1) print("DEFAULT_TARGETS is now %s" % [str(t) for t in DEFAULT_TARGETS]) prog2 = Program('prog2.c') Default(prog2) print("DEFAULT_TARGETS is now %s" % [str(t) for t in DEFAULT_TARGETS])
prog1.c
prog2.c

Which yields the output:

scons

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 have added the default targets you expect to find in it.

### Fetching the List of Build Targets, Regardless of Origin: the &BUILD_TARGETS; Variable

You have already seen 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; tries 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:

if COMMAND_LINE_TARGETS: targets = COMMAND_LINE_TARGETS else: targets = DEFAULT_TARGETS

&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.

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:

prog1 = Program('prog1.c') Program('prog2.c') Default(prog1) print("BUILD_TARGETS is %s" % [str(t) for t in BUILD_TARGETS])
prog1.c
prog2.c

Notice how the value of &BUILD_TARGETS; changes depending on whether a target is specified on the command line - &BUILD_TARGETS; takes from &DEFAULT_TARGETS; only if there are no &COMMAND_LINE_TARGETS;:

scons -Q
scons -Q prog2
scons -Q -c .