Search code examples
pythonwaf

Use output of waf Task in other waf Task


I want to use the target of a waf Task as source in another waf Task, but this does not work as expected.

A simple but complete example: I added two Tasks (t_1, t_2) I want to add as a feature and added their constraints by before and after.

  • In Task t_1 I use src=link_task.outputs[0] as src and link_task.outputs[0].change_ext('.txt') as tgt for the Task.

  • But in t_2 I want to use the output/target of t_1 as input. I assumed I can get it by referencing self.t_1.ouputs, but this seems to be wrong. Why does this work for in t_1 for the apply_link Task, but not for t_1?


  1. MWE: wscript

    from waflib import Context, Options
    from waflib import Task, TaskGen
    from waflib.Tools.compiler_c import c_compiler
    
    def options(opt):
            opt.load('compiler_c')
    
    def configure(cnf):
            cnf.load('compiler_c')
    
    def build(bld):
            bld.program(features=['t_1', 't_2'], source='main.c', target="abc")
    
    class t_1(Task.Task):
        always_run = True
        run_str = 'echo ${SRC} && echo hello t_1 > ${TGT}'
        color = 'RED'
    
    
    @TaskGen.feature('t_1')
    @TaskGen.after('apply_link')
    @TaskGen.before('t_2')
    def add_t_1_task(self):
        try:
            link_task = self.link_task
        except AttributeError as err:
            print err
            return
        self.create_task('t_1', src=link_task.outputs[0], tgt=link_task.outputs[0].change_ext('.txt'))
    
    
    class t_2(Task.Task):
        always_run = True
        run_str = 'echo ${SRC}'
        color = 'RED'
    
    
    @TaskGen.feature('t_2')
    @TaskGen.after('apply_link', 't_1')
    def add_t_2_task(self):
        try:
            t_1 = self.t_1
        except AttributeError as err:
            print err
            return
        self.create_task('t_2', src=t_1.outputs[0])
    

  1. Running python waf configure build leads to:

    user@laptop /cygdrive/c/work
    $ python waf-1.9.13 configure clean build
    Setting top to                           : /cygdrive/c/work
    Setting out to                           : /cygdrive/c/work/build
    Checking for 'gcc' (C compiler)          : /usr/bin/gcc
    'configure' finished successfully (0.150s)
    'clean' finished successfully (0.010s)
    Waf: Entering directory `/cygdrive/c/work/build'
    'task_gen' object has no attribute 't_1' <===================== How to get this working
    [1/3] Compiling main.c
    [2/3] Linking build/abc.exe
    [3/3] Compiling build/abc.exe
    abc.exe
    
    Waf: Leaving directory `/cygdrive/c/work/build'
    'build' finished successfully (0.270s)
    

Solution

  • The before and after decorators apply to task generator methods, not tasks. You should have:

    @TaskGen.feature('t_1')
    @TaskGen.after('apply_link')
    # correction: no need to use @TaskGen.before('add_t_2_task')
    def add_t_1_task(self):
    
        # correction: you have to define self.t_1
    
        self.t_1 = self.create_task(
            't_1',
            self.link_task.outputs[0], 
            self.link_task.outputs[0].change_ext('.txt')
        )
    
    @TaskGen.feature('t_2')
    @TaskGen.after('apply_link', 'add_t_1_task') # correction: use method name
    def add_t_2_task(self):
    
        # add_t-2_task is executed after add_t_1_task, so using self.t_1 is ok
    
        print "t_1", self.t_1
    

    By the way, do not use always_run=True as it defeats one of waf main feature, ie only build what you need to build :)