<?xml version='1.0'?>

<!--
SPDX-FileCopyrightText: Copyright The SCons Foundation (https://scons.org)
SPDX-License-Identifier: MIT
SPDX-FileType: DOCUMENTATION

This file is processed by the bin/SConsDoc.py module.
-->

<!DOCTYPE sconsdoc [
    <!ENTITY % scons SYSTEM "../scons.mod">
    %scons;

    <!ENTITY % builders-mod SYSTEM "../generated/builders.mod">
    %builders-mod;
    <!ENTITY % functions-mod SYSTEM "../generated/functions.mod">
    %functions-mod;
    <!ENTITY % tools-mod SYSTEM "../generated/tools.mod">
    %tools-mod;
    <!ENTITY % variables-mod SYSTEM "../generated/variables.mod">
    %variables-mod;

]>

<chapter id="chap-builders-commands"
         xmlns="http://www.scons.org/dbxsd/v1.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
<title>Not Writing a Builder:  the &Command; Builder</title>

  <!--

  =head2 The C<Command> method


  The C<Command> method is called as follows:

    Command $env <target>, <inputs>, <build action>;

  The target is made dependent upon the list of input files specified, and the
  inputs must be built successfully or Cons will not attempt to build the
  target.

  To specify a command with multiple targets, you can specify a reference to a
  list of targets. In Perl, a list reference can be created by enclosing a
  list in square brackets. Hence the following command:

    Command $env ['foo.h', 'foo.c'], 'foo.template', q(
  	gen %1
    );

  could be used in a case where the command C<gen> creates two files, both
  F<foo.h> and F<foo.c>.

  -->

  <para>

  Creating a &Builder; and attaching it to a &consenv;
  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
  &f-link-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 &b-link-Program;, &b-link-Object;, etc.),
  but takes as an additional argument
  the command to be executed to build the file:

  </para>

  <scons_example name="builderscommands_ex1">
     <file name="SConstruct" printme="1">
env = Environment()
env.Command('foo.out', 'foo.in', "sed 's/x/y/' &lt; $SOURCE > $TARGET")
     </file>
     <file name="foo.in">
foo.in
     </file>
  </scons_example>

  <para>

  When executed,
  &SCons; runs the specified command,
  substituting &cv-link-SOURCE; and &cv-link-TARGET;
  as expected:

  </para>

  <scons_output example="builderscommands_ex1" suffix="1">
    <scons_output_command>scons -Q</scons_output_command>
  </scons_output>

  <para>

  This is often more convenient than
  creating a &Builder; object
  and adding it to the &cv-link-BUILDERS; variable
  of a &consenv;.

  </para>

  <para>

  Note that the action you specify to the
  &Command; &Builder; can be any legal &SCons; &Action;,
  such as a Python function:

  </para>

  <scons_example name="builderscommands_ex2">
     <file name="SConstruct" printme="1">
env = Environment()

def build(target, source, env):
    # Whatever it takes to build
    return None

env.Command('foo.out', 'foo.in', build)
     </file>
     <file name="foo.in">
foo.in
     </file>
  </scons_example>

  <para>

  Which executes as follows:

  </para>

  <scons_output example="builderscommands_ex2" suffix="1">
    <scons_output_command>scons -Q</scons_output_command>
  </scons_output>

  <para>

  Note that &cv-link-SOURCE; and &cv-link-TARGET; are expanded
  in the source and target as well, so you can write:

  </para>

  <scons_example name="builderscommands_ex3">
     <file name="SConstruct" printme="1">
env.Command('${SOURCE.basename}.out', 'foo.in', build)
     </file>
  </scons_example>

  <para>

  which does the same thing as the previous example, but allows you
  to avoid repeating yourself.

  </para>

  <para>

  It may be helpful to use the <parameter>action</parameter>
  keyword to specify the action, is this makes things more clear
  to the reader:

  </para>

  <scons_example name="builderscommands_ex4">
     <file name="SConstruct" printme="1">
env.Command('${SOURCE.basename}.out', 'foo.in', action=build)
     </file>
  </scons_example>

  <para>

  The method described in
  <xref linkend="sect-controlling-build-output"/> for controlling
  build output works well when used with pre-defined builders which
  have pre-defined <literal>*COMSTR</literal> variables for that purpose,
  but that is not the case when calling &f-Command;,
  where &SCons; has no specific knowledge of the action ahead of time.
  If the action argument to &f-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 &f-Command;, which gives you much more control.
  Here's an evolution of the example from above showing this approach:

  </para>

  <scons_example name="builderscommands_ex5">
     <file name="SConstruct" printme="1">
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)
     </file>
     <file name="foo.in">
foo.in
     </file>
  </scons_example>

  <para>

  Which executes as follows:

  </para>

  <scons_output example="builderscommands_ex5" suffix="1">
    <scons_output_command>scons -Q</scons_output_command>
  </scons_output>

</chapter>
