Chapter 18. Not Writing a Builder: the `Command` Builder
Prev |  | Next

## Chapter 18. Not Writing a Builder: the `Command` Builder

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.

### Sidebar: Node Special Attributes

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

Prev |  | Next
17.8. Where To Put Your Custom Builders and Tools | Home | Chapter 19. Extending SCons: Pseudo-Builders and the AddMethod function