Python – How do I generate a multi-line build command?

How do I generate a multi-line build command?… here is a solution to the problem.

How do I generate a multi-line build command?

In SCons, my command builder creates ridiculously long command lines. ID
Love being able to split these commands into multiple lines
Build readability in logs.

For example I have a SConscipt:

import os

# create dependency
def my_cmd_generator(source, target, env, for_signature):
    return r'''echo its a small world after all \
        its a small world after all'''

my_cmd_builder = Builder(generator=my_cmd_generator, suffix = '.foo')

env = Environment()
env. Append( BUILDERS = {'MyCmd' : my_cmd_builder } )

my_cmd = env. MyCmd('foo.foo',os.popen('which bash').read().strip())
AlwaysBuild(my_cmd)

When it executes, I get:

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
echo its a small world after all \
its a small world after all
its a small world after all
sh: line 1: its: command not found
scons: *** [foo.foo] Error 127
scons: building terminated because of errors.

Do this in a python shell with os.system and os.popen — I get a readable command string, and the subshell process interprets all the lines as one command.

>>> import os
>>> cmd = r'''echo its a small world after all \
... its a small world after all'''
>>> print cmd
echo its a small world after all \
its a small world after all
>>> os.system( cmd)
its a small world after all its a small world after all
0

When I do this in SCons, it executes each row at a time, ie
Not what I wanted.

I also want to avoid building my commands into shell scripts, and
Then execute the shell script as this will create the string
Escape the madness.

Is this possible?

Update:
Kurnapey,
Thanks for the clue about $CCCOMSTR. Unfortunately, I’m not using any of the languages that SCons supports out of the box, so I’m creating my own command generator. Using the generator, how to get SCons to do the following:

echo its a small world after all its a small world after all' 

But print

echo its a small world after all \
    its a small world after all

?

Solution

Thanks to cournape’s tips on Actions and Generators (and the eclipse pydev debugger), I finally figured out what I needed to do. You want to pass your function to the “Builder” class as “Action” instead of “Generator”. This will allow you to make os.system or os.popen calls directly. Here is the updated code:

import os

def my_action(source, target, env):
    cmd = r'''echo its a small world after all \
        its a small world after all'''
    print cmd
    return os.system(cmd)

my_cmd_builder = Builder(
    action=my_action,  # <-- CRUCIAL PIECE OF SOLUTION
    suffix = '.foo')

env = Environment()
env. Append( BUILDERS = {'MyCmd' : my_cmd_builder } )

my_cmd = env. MyCmd('foo.foo',os.popen('which bash').read().strip())

This SConstruct file will produce the following output:

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
my_action(["foo.foo"], ["/bin/bash"])
echo its a small world after all \
        its a small world after all
its a small world after all its a small world after all
scons: done building targets.

Another key part is to remember that switching from “generator” to “action” means that the target you’re building no longer implicitly depends on the actual string you’re passing to the child process shell. You can recreate this dependency by adding the string to your environment.

For example, the solution I personally would like is as follows:

import os

cmd = r'''echo its a small world after all \
        its a small world after all'''

def my_action(source, target, env):
    print cmd
    return os.system(cmd)

my_cmd_builder = Builder(
    action=my_action,
    suffix = '.foo')

env = Environment()
env['_MY_CMD'] = cmd  # <-- CREATE IMPLICIT DEPENDENCY ON CMD STRING
env. Append( BUILDERS = {'MyCmd' : my_cmd_builder } )

my_cmd = env. MyCmd('foo.foo',os.popen('which bash').read().strip())

Related Problems and Solutions