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"])
Note that $SOURCE
and $TARGET
are expanded
in the source and target as well, so you can write:
env.Command('${SOURCE.basename}.out', 'foo.in', build)
which does the same thing as the previous example, but allows you to avoid repeating yourself.
It may be helpful to use the action
keyword to specify the action, is this makes things more clear
to the reader:
env.Command('${SOURCE.basename}.out', 'foo.in', action=build)
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.
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('foo.out', 'foo.in', action=act)
Which executes as follows:
% scons -Q
Building foo.out