tags:

views:

552

answers:

2

I want to inject a "Cleanup" target which depends on a number of other targets finishing before it goes off and gzip's some log files. It's important that I not gzip early as this can cause some of the tools to fail.

How can I inject a cleanup target for Scons to execute?

e.g. I have targets foo and bar. I want to inject a new custom target called 'cleanup' that depends on foo and bar and runs after they're both done, without the user having to specify

% scons foo cleanup

I want them to type:

% scons foo

but have scons execute as though the user had typed

% scons foo cleanup

I've tried creating the cleanup target and appending to sys.argv, but it seems that scons has already processed sys.argv by the time it gets to my code so it doesn't process the 'cleanup' target that I manually append to sys.argv.

+1  A: 

One way is to have the gzip tool depend on the output of the log files. For example, if we have this C file, 'hello.c':

#include <stdio.h>
int main()
{
    printf("hello world\n");
    return 0;
}

And this SConstruct file:

#!/usr/bin/python
env = Environment()
hello = env.Program('hello', 'hello.c')
env.Default(hello)
env.Append(BUILDERS={'CreateLog':
    Builder(action='$SOURCE.abspath > $TARGET', suffix='.log')})
log = env.CreateLog('hello', hello)
zipped_log = env.Zip('logs.zip', log)
env.Alias('cleanup', zipped_log)

Then running "scons cleanup" will run the needed steps in the correct order:

gcc -o hello.o -c hello.c
gcc -o hello hello.o
./hello > hello.log
zip(["logs.zip"], ["hello.log"])

This is not quite what you specified, but the only difference between this example and your requirement is that "cleanup" is the step that actually creates the zip file, so that is the step that you have to run. Its dependencies (running the program that generates the log, creating that program) are automatically calculated. You can now add the alias "foo" as follows to get the desired output:

env.Alias('foo', zipped_log)
rq
Thanks for the ideas. The thing is, I'm doing a build flow that has pieces which I don't completely control, so I can't pre-register log files to be zipped because I don't know all the log files being created.
Ross Rogers
+1  A: 

In version 1.1.0.d20081104 of SCons, you can use the private internal SCons method:

SCons.Script._Add_Targets( [ 'MY_INJECTED_TARGET' ] )

If the user types:

% scons foo bar

The above code snippet will cause SCons to behave as though the user had typed:

% scons foo bar MY_INJECTED_TARGET
Ross Rogers
Undocumented features FTW! :-) I find I often just end up grepping the source for SCons when I hit these "unsolvable" problems...
rq
Does this break when the --random flag is used? The order in which user-supplied targets are built is undefined, as far as I know.
BennyG
I inject the target but have dependencies on other targets, so it fits snuggly in the graph. Even if you do ``-random``, it will only randomize concurrent steps -- not steps which have dependencies on each other. Dependencies are always satisfied before the depending target build command starts executing.
Ross Rogers