title: Writing a custom builder that executes external command and python function
body: <p>I'm looking to write a custom SCons Builder that:</p>
  
  <ol>
  <li>Executes an external command to produce <code>foo.temp</code></li>
  <li>Then executes a python function to manipulate <code>foo.temp</code> and produce the final output file</li>
  </ol>
  
  <p>I've referred to the two following sections, but I'm not sure the correct way to "glue" them together.</p>
  
  <ul>
  <li><a href="http://www.scons.org/doc/2.3.4/HTML/scons-user.html#idp14704984" rel="nofollow">18.1. Writing Builders That Execute External Commands</a></li>
  <li><a href="http://www.scons.org/doc/2.3.4/HTML/scons-user.html#idp14732648" rel="nofollow">18.4. Builders That Execute Python Functions</a></li>
  </ul>
  
  <p>I know that <a href="http://www.scons.org/doc/2.3.4/HTML/scons-user.html#f-Command" rel="nofollow"><code>Command</code></a> accepts a list of actions to take. But how do I properly handle that intermediate file? Ideally the intermediate file would be invisible to the user -- the entire Builder would appear to operate atomically.</p>
  
  <hr>
  
  <p>Here's what I've come up with that seems to be working. However the <code>.bin</code> file isn't being deleted automatically.</p>
  
  
  
  <pre class="lang-python prettyprint-override"><code>from SCons.Action import Action
  from SCons.Util import is_List
  from SCons.Script import Delete
  
  _objcopy_builder = Builder(
          action = 'objcopy -O binary $SOURCE $TARGET',
          suffix = '.bin',
          single_source = 1
          )
  
  def _add_header(target, source, env):
      source = str(source[0])
      target = str(target[0])
  
      with open(source, 'rb') as src:
          with open(target, 'wn') as tgt:
              tgt.write('MODULE\x00\x00')
              tgt.write(src.read())
      return 0
  
  _addheader_builder = Builder(
          action = _add_header,
          single_source = 1
          )
  
  def Elf2Mod(env, target, source, *args, **kw):
      def check_one(x, what):
          if not is_List(x):
              x = [x]
          if len(x) != 1:
              raise StopError('Only one {0} allowed'.format(what))
          return x
      target = check_one(target, 'target')
      source = check_one(source, 'source')
  
      # objcopy a binary file
      binfile = _objcopy_builder.__call__(env, source=source, **kw)
  
      # write the module header
      _addheader_builder.__call__(env, target=target, source=binfile, **kw)
  
      # delete the intermediate binary file
      # TODO: Not working
      Delete(binfile)
  
      return target
  
  def generate(env):
      """Add Builders and construction variables to the Environment."""
      env.AddMethod(Elf2Mod, 'Elf2Mod')
      print 'Added Elf2Mod to env {0}'.format(env)
  
  def exists(env):
      return True
  </code></pre>