Reputation: 938
scons experts -
Scons thinks that this failing command succeeds, and running scons another time indicates all targets are up-to-date. The fribbleblat
command doesn't exist. This behavior occurs when a 'middle' command in a pipeline fails, but not when the last command in the pipeline fails.
How can I propagate errors in piped commands to scons?
import os
from SCons.Script import Environment
env = Environment()
env.Command(source='foo',
target='bar',
action='cat $SOURCE | fribbleblat | cat >$TARGET')
Running it twice demonstrates that scons thinks it has built the target correctly.
[edit: I created a file 'foo' with random content, echo dslkfjds >foo
]
$ scons -f SConstruct.exp
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cat foo | fribbleblat | cat > bar
sh: 1: fribbleblat: not found
cat: write error: Broken pipe
scons: done building targets.
$ scons -f SConstruct.exp
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
scons: `.' is up to date.
scons: done building targets.
$ scons --version
SCons by Steven Knight et al.:
script: v2.3.0.rel_2.3.0:2870:c8dbbaa4598e, 2013/07/31 13:02:49, by bdbaddog on Williams-MacBook
engine: v2.3.0, 2013/03/03 09:48:35, by garyo on reepicheep
engine path: ['/usr/lib/scons/SCons']
Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 The SCons Foundation
Upvotes: 0
Views: 409
Reputation: 938
dirkbaechle is right - Turns out this isn't so much an scons question as a shell question. A little more searching led me to the following answers:
The short answer is 'set -o pipefail', but that only works in bash
, ksh
, and zsh
, but not in sh
, so I had to make sure scons was invoking bash
as well.
The following scons file works as expected and catches the failed command.
import os
from SCons.Script import Environment
env = Environment()
env['SHELL'] = 'bash'
env['ENV']['SHELLOPTS'] = 'pipefail'
env.Command(source='foo',
target='bar',
action='cat $SOURCE | fribbleblat | cat >$TARGET')
Upvotes: 2
Reputation: 4052
Your assumption is wrong: it's not SCons that thinks the command was successful. On my Linux system the command
> cat test.txt | fribblecat | cat > out.txt
yields "fribblecat: command not found." and an immediate
> echo $?
gives a "0" (success) as result. So the shell opens the output file, and signals a success to SCons. You have to find a way to let the pipe sequence fail on the shell level, e.g. by wrapping your commands in a shell script that checks whether the executable "fribblecat" actually exists. Another option would be to write a simple "fribblecat" Builder, assuming that the executable supports command-line options for the input and output file:
env = Environment()
env.Command('out.txt','test.txt','fribblecat -o $TARGET $SOURCE')
Check out the UserGuide "18. Writing Your Own Builders" ( http://www.scons.org/doc/production/HTML/scons-user.html ), and our guide for writing Tools at http://www.scons.org/wiki/ToolsForFools .
Upvotes: 2