While building my program it is important to distinguish between files that don't exists and files that are empty.
However, it appears that scons
treats them the same and neglect to rebuild a target when a source file changed from one of these states to the other one.
Step 0:
SConstruct
foo = Command('foo', [], 'echo $TARGET is not created here!')
bar = Command('bar', foo, 'touch $TARGET ; test -f $SOURCE')
Default(bar)
Result:
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
echo foo is not created here!
foo is not created here!
touch bar ; test -f foo
scons: *** [bar] Error 1
scons: building terminated because of errors.
My interpretation:
The command for foo
fails to create the file but it doesn't raise and error so the command for bar
is run. It checks if foo
exists and returns an error. Build fails (everything as expected so far).
Step 1:
SConstruct:
foo = Command('foo', [], 'touch $TARGET')
bar = Command('bar', foo, 'touch $TARGET ; test -f $SOURCE')
Default(bar)
Result:
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
touch foo
touch bar ; test -f foo
scons: done building targets.
My interpretation:
foo
is rebuilt because it has changed. This time it creates an empty file. bar
is rebuild because it failed before. It succeeds this time. The build is successful (still as expected).
Step 2:
SConstruct
foo = Command('foo', [], 'echo $TARGET is not created here!')
bar = Command('bar', foo, 'touch $TARGET ; test -f $SOURCE')
Default(bar)
Result:
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
echo foo is not created here!
foo is not created here!
scons: `bar' is up to date.
scons: done building targets.
My interpretation:
foo
is rebuilt because it has changed again (was restores to the previous version). The file foo
doesn't exist any longer because scons
removes files before building them and the command fails to recreate it. bar
is not rebuilt because scons
doesn't seem to detect a change in the source file.
The build is successful while it shouldn't!
How can I force scons
to rebuild bar
in the last step?
The solution should scale well to "foo" commands that produce many files, list of which is generated programmatically in SConscript
and cannot be hard-coded.
By the way, scons does now distinguish between emtpy and nonexistent, that's a fairly recent change (commit 3b7f8b4ce0, github.com/SCons/scons/pull/3833).