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.
You can control
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 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)
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. Found nothing to build %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
SCons supports 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])
(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 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])
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.
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 %s" % [str(t) for t in BUILD_TARGETS])
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
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