Creating a Builder and attaching it to a construction environment
allows for a lot of flexibility when you
want to re-use actions
to build multiple files of the same type.
This can, however, be cumbersome
if you only need to execute one specific command
to build a single file (or group of files).
For these situations, SCons supports a
Command builder that arranges
for a specific action to be executed
to build a specific file or files.
This looks a lot like the other builders
(like Program, Object, etc.),
but takes as an additional argument
the command to be executed to build the file:
env = Environment()
env.Command('foo.out', 'foo.in', "sed 's/x/y/' < $SOURCE > $TARGET")
When executed,
SCons runs the specified command,
substituting $SOURCE and $TARGET
as expected:
% scons -Q
sed 's/x/y/' < foo.in > foo.out
This is often more convenient than
creating a Builder object
and adding it to the $BUILDERS variable
of a construction environment.
Note that the action you specify to the
Command Builder can be any legal SCons Action,
such as a Python function:
env = Environment()
def build(target, source, env):
# Whatever it takes to build
return None
env.Command('foo.out', 'foo.in', build)
Which executes as follows:
% scons -Q
build(["foo.out"], ["foo.in"])
$SOURCE and $TARGET are expanded
in the source and target as well:
env.Command('${SOURCE.base}.out', File('foo.in'), build)
Which does the same thing as the previous example, but allows you
to write a more generic rule for transforming the source filename
to the target filename, since unlike regular Builders,
Command does not have any built-in rules for that.
The example uses a Node special attribute
(.base, the file without its suffix),
a concept which has not been introduced yet,
but will appear in several subsequent examples
(see details in the Reference Manual section
Substitution: Special Attributes).
Due to the quirks of SCons' deferred evaluation scheme,
node special attribues do not currently work
in source and target arguments if the
replacement is a string (like 'foo.in').
They do work fine in strings describing actions.
You can give SCons a little help by
manually converting the filename string to a Node
(see Section 5.2, “Explicitly Creating File and Directory Nodes”),
which is the approach used in the example.
The method described in
Section 9.2, “Controlling How SCons Prints Build Commands: the $*COMSTR Variables” for controlling
build output works well when used with pre-defined builders which
have pre-defined *COMSTR variables for that purpose,
but that is not the case when calling Command,
where SCons has no specific knowledge of the action ahead of time.
If the action argument to Command is not already an Action object,
it will construct one for you with suitable defaults,
which include a message based on the type of action.
However, you can also construct the Action object yourself
to pass to Command, which gives you much more control.
Using the action keyword can also help
make such lines easier to read.
Here's an evolution of the example from above showing this approach:
env = Environment()
def build(target, source, env):
# Whatever it takes to build
return None
act = Action(build, cmdstr="Building ${TARGET}")
env.Command('${SOURCE.base}.out', File('foo.in'), action=act)
Which executes as follows:
% scons -Q
Building foo.out