[Scons-users] SCons builder to call scripts with other files as arguments

Carnë Draug carandraug+dev at gmail.com
Sun Jan 24 17:33:22 EST 2016


On 24 January 2016 at 21:24, Bill Deegan <bill at baddogconsulting.com> wrote:
> On Sun, Jan 24, 2016 at 2:15 PM, Carnë Draug <carandraug+dev at gmail.com>
> wrote:
>>
>> I have many cases where I use scripts and data files in SCons.  At the
>> moment I'm writing something like this:
>>
>>     foo_script = 'scripts/mk_foo.py'
>>     foo = env.Command(source = 'data/foo.json',
>>                       target = 'results/foo.tex',
>>                       action = 'python %s $SOURCE > $TARGET')
>>     env.Depends(foo, foo_script)
>>
>> This is already not ideal because I have to keep repeating 'foo_script'.
>> However, my problem is another which I think also solves it.
>>
>> I have changed the structure of my project and started to make use of
>> SConscript in subdirectory.  When using a SConscript, SCons builders
>> are smart enough to fix the path for the declared nodes ("source" and
>> "target") but obviously not for the actual path of the script.
>>
>> Short of exporting one more variable from SConstruct and join the paths
>> myself, how can I do this with SCons?
>>
>> Carnë
>
> Add a builder for mk_foo.py, in the emitter add the dependency on the
> script.
> (see: https://bitbucket.org/scons/scons/wiki/ToolsForFools)
> and/or add a psuedo builder.
> (see: http://scons.org/doc/production/HTML/scons-user/ch20.html)

A builder for each of the many scripts seem excessive.  So I made it
work with a pseudo builder.

I first found out that this works:

    foo = env.Command(source = ['scripts/mk_foo.py',
                                'data/foo.json'],
                      target = 'results/foo.tex',
                      action = 'python $SOURCES > $TARGET')

which was pretty nice.  All the paths are expanded nicely even within
a SConscript.

However, I didn't like the idea of mixing both script and input
arguments in SOURCES.  I also wanted more flexibility for python.
So I wrote a general builder to call on python scripts:

    vars = Variables()
    vars.Add('PYTHON', default='python', help='The python interpreter')
    vars.Update(env)

    def python_output(env, script, source, target, args=[]):
      script = env.File(script)
      c = env.Command(target, source, SCRIPT=script, ARGS=args,
                      action='$PYTHON $SCRIPT $SOURCE $ARGS > $TARGET')
      env.Depends(c, script)
      return c

    env.AddMethod(python_output, "PythonOutput")

    foo = env.PythonOutput(script = 'scripts/mk_foo.py',
                           source = 'data/foo.json',
                           target = 'results/foo.tex')

The trick required was on using File().  It works different outside of
a builder which took me forever to realize.

Carnë


More information about the Scons-users mailing list