In SCons, my command generators create ridiculously long command lines. I’d like to be able to split these commands across multiple lines for readability in the build log.
e.g. I have a SConscipt like:
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.
Doing this in the python shell with os.system and os.popen works — I get a readable command string and the sub-shell 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 line one at a time, which is not what I want.
I also want to avoid building up my commands into a shell-script and then executing the shell script, because that will create string escaping madness.
Is this possible?
UPDATE:
cournape,
Thanks for the clue about the $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 a generator, how can I get SCons to do:
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
?
Thanks to cournape’s tip about Actions versus Generators ( and eclipse pydev debugger), I’ve finally figured out what I need to do. You want to pass in your function to the ‘Builder’ class as an ‘action’ not a ‘generator’. This will allow you to actually execute the os.system or os.popen call directly. Here’s the updated code:
This SConstruct file will produce the following output:
The other crucial piece is to remember that switching from a ‘generator’ to an ‘action’ means the target you’re building no longer has an implicit dependency on the actual string that you are passing to the sub-process shell. You can re-create this dependency by adding the string into your environment.
e.g., the solution that I personally want looks like: