&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: 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 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 , 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 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 , below.
Command-Line Options &SCons; has many command-line options that control its behavior. A &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 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 -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 command-line options that you want &SCons; to use. If, for example, you're using a POSIX shell that's compatible with the Bourne shell, and you always want &SCons; to use the -Q option, you can set the &SCONSFLAGS; environment as follows: % scons scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... ... [build output] ... scons: done building targets. % export SCONSFLAGS="-Q" % scons ... [build output] ... Users of &csh;-style shells on POSIX systems can set the &SCONSFLAGS; environment as follows: $ setenv SCONSFLAGS "-Q" Windows users may typically want to set the &SCONSFLAGS; in the appropriate tab of the System Properties window.
Getting Values Set by Command-Line Options: the &GetOption; Function &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 -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 the command-line help available to users by using the &GetOption; function to load the subsidiary &SConscript; files only if the the user has not specified the -h or --help option, like so: if not GetOption('help'): SConscript('src/SConscript', export='env') 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 section, below.
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 &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 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 -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 provide 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", GetOption('num_jobs') 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 running with -j 2 scons: `.' is up to date. But if the $NUM_CPU environment variable is set, then we use that for the default number of jobs: % export NUM_CPU="4" % scons -Q running with -j 4 scons: `.' is up to date. But any explicit -j or --jobs value the user specifies an the command line is used first, regardless of whether or not the $NUM_CPU environment variable is set: % scons -Q -j 7 running with -j 7 scons: `.' is up to date. % export NUM_CPU="4" % scons -Q -j 3 running with -j 3 scons: `.' is up to date.
Strings for Getting or Setting Values of &SCons; Command-Line Options 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: --), after replacing any remaining hyphen characters with underscores. 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_disable cache_force cache_show clean , , config directory , diskcheck duplicate file , , , help , ignore_errors implicit_cache implicit_deps_changed implicit_deps_unchanged interactive , keep_going , max_drift no_exec , , , , no_site_dir num_jobs , profile_file question , random repository , , silent , , site_dir stack_size taskmastertrace_file warn
Adding Custom Command-Line Options: the &AddOption; Function &SCons; also allows you to define your own command-line options with the &AddOption; function. The &AddOption; function takes the same arguments as the optparse.add_option function from the standard Python library. The &AddOption; function is, in fact, implemented using a subclass of the optparse.OptionParser. 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.) One useful example of using this functionality is to provide a for users: 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) The above code uses the &GetOption; function to set the $PREFIX construction variable to any value that the user specifies with a command-line option of --prefix. Because $PREFIX will expand to a null string if it's not initialized, running &SCons; without the option of --prefix will install the file in the /usr/bin/ directory: % scons -Q -n Install file: "foo.in" as "/usr/bin/foo.in" 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 Install file: "foo.in" as "/tmp/install/usr/bin/foo.in"
Command-Line <varname>variable</varname>=<varname>value</varname> Build Variables You may want to control various aspects of your build by allowing the user to specify variable=value values on the command line. For example, suppose you want users 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 that users always specify a variable, you probably want to use the Python ARGUMENTS.get() function, which allows you to specify a default value to be used if there is no specification on the command line.) The following code sets the &cv-link-CCFLAGS; construction variable 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') This results in the -g compiler option being used when debug=1 is used on the command line: % scons -Q debug=0 cc -o prog.o -c prog.c cc -o prog prog.o % scons -Q debug=0 scons: `.' is up to date. % scons -Q debug=1 cc -o prog.o -c -g prog.c cc -o prog prog.o % scons -Q debug=1 scons: `.' is up to date. Notice that &SCons; keeps track of the last values used to build the object files, and as a result correctly rebuilds the object and executable files only 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 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. 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 to let the user add to the &CPPDEFINES; construction variable 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') Yields the following output: % scons -Q define=FOO cc -o prog.o -c -DFOO prog.c % scons -Q define=FOO define=BAR cc -o prog.o -c -DFOO -DBAR prog.c Note that the &ARGLIST; and &ARGUMENTS; variables do not interfere with each other, but merely provide slightly different views into how the user 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 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).
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 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. 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 -D 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: 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']) This &SConstruct; file first creates a &Variables; object (the vars = Variables() 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 0 (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. 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: % scons -Q RELEASE=1 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 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 they have been officially deprecated as of &SCons; version 2.0.
Providing Help for Command-Line Build Variables 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 scons -h. 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: vars = Variables('custom.py') vars.Add('RELEASE', 'Set to 1 to build for release', 0) env = Environment(variables = vars) Help(vars.GenerateHelpText(env)) &SCons; will now display some useful text when the -h option is used: % scons -Q -h RELEASE: Set to 1 to build for release default: 0 actual: 0 Use scons -H for help about command-line options. Notice that the help output shows the default value, and the current actual value of the build variable.
Reading Build Variables From a File 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: 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)) This then allows the user to control the &RELEASE; variable by setting it in the &custom_py; file: RELEASE = 1 Note that this file is actually executed like a Python script. Now when we run &SCons;: % scons -Q 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 And if we change the contents of &custom_py; to: RELEASE = 0 The object files are rebuilt appropriately with the new variable: % scons -Q 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
Pre-Defined Build Variable Functions &SCons; provides a number of functions that provide ready-made behaviors for various types of command-line build variables.
True/False Values: the &BoolVariable; Build Variable Function 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;. 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', 'Set to build for release', 0)) env = Environment(variables = vars, CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) env.Program('foo.c') With this build variable, the &RELEASE; variable can now be enabled by setting it to the value yes or t: % scons -Q RELEASE=yes foo.o cc -o foo.o -c -DRELEASE_BUILD=True foo.c % scons -Q RELEASE=t foo.o cc -o foo.o -c -DRELEASE_BUILD=True foo.c 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 cc -o foo.o -c -DRELEASE_BUILD=False foo.c % scons -Q RELEASE=f foo.o cc -o foo.o -c -DRELEASE_BUILD=False foo.c Other values that equate to &false; include n, 0, off and none. Lastly, if a user tries to specify any other value, &SCons; supplies an appropriate error message: % scons -Q RELEASE=bad_value foo.o scons: *** Error converting option: RELEASE Invalid value for boolean option: bad_value File "/home/my/project/SConstruct", line 4, in <module>
Single Value From a List: the &EnumVariable; Build Variable Function 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: 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') The user can now explicity set the &COLOR; build variable to any of the specified allowed values: % scons -Q COLOR=red foo.o cc -o foo.o -c -DCOLOR="red" foo.c % scons -Q COLOR=blue foo.o cc -o foo.o -c -DCOLOR="blue" foo.c % scons -Q COLOR=green foo.o cc -o foo.o -c -DCOLOR="green" foo.c But, almost more 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 scons: *** Invalid value for option COLOR: magenta File "/home/my/project/SConstruct", line 5, in <module> 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 navy as a synonym for blue. We do this by adding a ↦ dictionary that will map its key values to the desired legal value: 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') As desired, the user can then use navy on the command line, and &SCons; will translate it into blue when it comes time to use the &COLOR; variable to build a target: % scons -Q COLOR=navy foo.o cc -o foo.o -c -DCOLOR="blue" foo.c By default, when using the &EnumVariable; function, arguments that differ from the legal values only in case are treated as illegal values: % scons -Q COLOR=Red foo.o scons: *** Invalid value for option COLOR: Red File "/home/my/project/SConstruct", line 5, in <module> % scons -Q COLOR=BLUE foo.o scons: *** Invalid value for option COLOR: BLUE File "/home/my/project/SConstruct", line 5, in <module> % scons -Q COLOR=nAvY foo.o scons: *** Invalid value for option COLOR: nAvY File "/home/my/project/SConstruct", line 5, in <module> 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', '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') Which yields the output: % scons -Q COLOR=Red foo.o cc -o foo.o -c -DCOLOR="Red" foo.c % scons -Q COLOR=BLUE foo.o cc -o foo.o -c -DCOLOR="BLUE" foo.c % scons -Q COLOR=nAvY foo.o cc -o foo.o -c -DCOLOR="blue" foo.c % scons -Q COLOR=green foo.o cc -o foo.o -c -DCOLOR="green" foo.c Notice that an &ignorecase; value of 1 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 2: 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') Now &SCons; will use values of red, green or blue regardless of how the user spells those values on the command line: % scons -Q COLOR=Red foo.o cc -o foo.o -c -DCOLOR="red" foo.c % scons -Q COLOR=nAvY foo.o cc -o foo.o -c -DCOLOR="blue" foo.c % scons -Q COLOR=GREEN foo.o cc -o foo.o -c -DCOLOR="green" foo.c
Multiple Values From a List: the &ListVariable; Build Variable Function 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: 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') 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: % scons -Q COLORS=red,blue foo.o cc -o foo.o -c -DCOLORS="red blue" foo.c % scons -Q COLORS=blue,green,red foo.o cc -o foo.o -c -DCOLORS="blue green red" foo.c 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: % scons -Q COLORS=all foo.o cc -o foo.o -c -DCOLORS="red green blue" foo.c % scons -Q COLORS=none foo.o cc -o foo.o -c -DCOLORS="" foo.c And, of course, an illegal value still generates an error message: % scons -Q COLORS=magenta foo.o scons: *** Error converting option: COLORS Invalid value(s) for option: magenta File "/home/my/project/SConstruct", line 5, in <module>
Path Names: the &PathVariable; Build Variable Function &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: 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') This then allows the user to override the &CONFIG; build variable on the command line as necessary: % scons -Q foo.o cc -o foo.o -c -DCONFIG_FILE="/etc/my_config" foo.c % scons -Q CONFIG=/usr/local/etc/other_config foo.o scons: `foo.o' is up to date. By default, &PathVariable; checks to make sure that the specified path exists and generates an error if it doesn't: % scons -Q CONFIG=/does/not/exist foo.o scons: *** Path for option CONFIG does not exist: /does/not/exist File "/home/my/project/SConstruct", line 6, in <module> &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: 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') Conversely, to ensure that any specified paths are directories and not files, use the &PathVariable_PathIsDir; method: 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') 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: 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') 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: 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')
Enabled/Disabled Path Names: the &PackageVariable; Build Variable Function 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 yes or no keywords, in addition to allow them to supply an explicit path name. &SCons; supports the &PackageVariable; function to support this: vars = Variables('custom.py') vars.Add(PackageVariable('PACKAGE', 'Location package', '/opt/location')) env = Environment(variables = vars, CPPDEFINES={'PACKAGE' : '"$PACKAGE"'}) env.Program('foo.c') 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: % scons -Q foo.o cc -o foo.o -c -DPACKAGE="/opt/location" foo.c % scons -Q PACKAGE=/usr/local/location foo.o cc -o foo.o -c -DPACKAGE="/usr/local/location" foo.c % scons -Q PACKAGE=yes foo.o cc -o foo.o -c -DPACKAGE="True" foo.c % scons -Q PACKAGE=no foo.o cc -o foo.o -c -DPACKAGE="False" foo.c
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 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: 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), )
Handling Unknown Command-Line Build Variables: the &UnknownVariables; Function 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.) 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 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: 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') The &UnknownVariables; method returns a dictionary containing the keywords and values of any variables the user 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). 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;: % scons -Q NOT_KNOWN=foo Unknown variables: ['NOT_KNOWN'] 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 construction environment with the variables= keyword argument of an &Environment; call.
Command-Line Targets
Fetching Command-Line Targets: the &COMMAND_LINE_TARGETS; Variable &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: if 'bar' in COMMAND_LINE_TARGETS: print "Don't forget to copy `bar' to the archive!" Default(Program('foo.c')) Program('bar.c') 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: % scons -Q cc -o foo.o -c foo.c cc -o foo foo.o % scons -Q bar Don't forget to copy `bar' to the archive! cc -o bar.o -c bar.c cc -o bar bar.o 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 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: env = Environment() hello = env.Program('hello.c') env.Program('goodbye.c') Default(hello) This &SConstruct; file knows how to build two programs, &hello; and &goodbye;, but only builds the &hello; program by default: % scons -Q cc -o hello.o -c hello.c cc -o hello hello.o % scons -Q scons: `hello' is up to date. % scons -Q goodbye cc -o goodbye.o -c goodbye.c cc -o goodbye goodbye.o 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 . cc -o goodbye.o -c goodbye.c cc -o goodbye goodbye.o cc -o hello.o -c hello.c cc -o hello hello.o 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) 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 will build only the prog1 and prog3 programs by default: % scons -Q cc -o prog1.o -c prog1.c cc -o prog1 prog1.o cc -o prog3.o -c prog3.c cc -o prog3 prog3.o % scons -Q . cc -o prog2.o -c prog2.c cc -o prog2 prog2.o 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') In which case only the target(s) in that directory will be built by default: % scons -Q 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 % scons -Q scons: `prog1' is up to date. % scons -Q . 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 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) Which would produce build output like: % scons -Q scons: *** No targets specified and no Default() targets found. Stop. % scons -Q . cc -o prog1.o -c prog1.c cc -o prog1 prog1.o cc -o prog2.o -c prog2.c cc -o prog2 prog2.o
Fetching the List of Default Targets: the &DEFAULT_TARGETS; Variable &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 map function to run the list through str: prog1 = Program('prog1.c') Default(prog1) print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS) (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 -Q flag when we run &SCons;:) % scons 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. 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: 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) Which yields the output: % scons 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. 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.
Fetching the List of Build Targets, Regardless of Origin: the &BUILD_TARGETS; Variable 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: 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", map(str, BUILD_TARGETS) Notice how the value of &BUILD_TARGETS; changes depending on whether a target is specified on the command line: % scons -Q BUILD_TARGETS is ['prog1'] cc -o prog1.o -c prog1.c cc -o prog1 prog1.o % scons -Q prog2 BUILD_TARGETS is ['prog2'] cc -o prog2.o -c prog2.c cc -o prog2 prog2.o % scons -Q -c . BUILD_TARGETS is ['.'] Removed prog1.o Removed prog1 Removed prog2.o Removed prog2