builddependencieswaf

How to declare WAF dependency of test script on built program?


I am struggling to find the correct way to define the dependency of a test script on a binary program that waf builds in the same build process. Here is a minimum example of the wscript:

from waflib.Tools import waf_unit_test

def options(opt):
    opt.load("compiler_cxx python waf_unit_test")

def configure(cnf):
    cnf.load("compiler_cxx python waf_unit_test")


def build(bld):
    bld.add_post_fun(waf_unit_test.summary)
    bld.options.clear_failed_tests= True

    bld(features= "cxx cxxprogram",
        target= "foo",
        source= "foo.cpp")

    tg= bld(features= "test_scripts",
        test_scripts_source= "fooTest.py",
        test_scripts_template= "${PYTHON} ${SRC}")
    tg.post()
    tg.tasks[0].inputs.append(bld.path.find_or_declare("foo"))

I want to express that waf shall build the program foo. Then, if the program foo has changed since the last build run, the script fooTest.py shall check the execution of that program. The wscript above works:

Waf: Entering directory `/home/x/tmp/exe_depend/build'
[1/3] Compiling foo.cpp
[2/3] Linking build/foo
[3/3] Processing utest: fooTest.py build/foo
Waf: Leaving directory `/home/x/tmp/exe_depend/build'
execution summary 
  tests that pass 1/1 
    /home/x/tmp/exe_depend/fooTest.py 
  tests that fail 0/1 
'build' finished successfully (0.054s)

In principle, the wscript above fulfills my needs but it looks ugly as a hack and it seems wrong to fiddle with the task generator tg. Does anyone of you knows a smooth solution?


Solution

  • Well, there's no many hooks in waf_unit_test.py. the best way is to extend it by making your own tool and putting your 2 lines of code in it. Something like that:

    # in file my_unit_test.py
    
    def options(opt):
        opt.load("waf_unit_test") # we extend it, no need to recode
    
    def configure(conf):
        conf.load("waf_unit_test") # we extend it, no need to recode
    
    @feature('test_scripts')
    @after_method('make_interpreted_test') # we execute after task creation
    def process_test_scripts_dependencies(self):
        try:
            self.test_scripts_deps
        except AttributeError:
            return
    
        for task in self.tasks: # there can be many scripts
            task.set_inputs(self.to_nodes(self.test_scripts_deps))
    

    Using it:

    def options(opt):
        opt.load("compiler_cxx python my_unit_test")
    
    def configure(cnf):
        cnf.load("compiler_cxx python my_unit_test")
    
    
    def build(bld):
        bld.add_post_fun(waf_unit_test.summary)
        bld.options.clear_failed_tests= True
    
        myprogram = "foo"
    
        bld(
            features = "cxx cxxprogram",
            target = myprogram,
            source = "foo.cpp",
        )
    
        bld(
            features = "test_scripts",
            test_scripts_deps = myprogram,
            test_scripts_source = "fooTest.py",
            test_scripts_template = "${PYTHON} ${SRC}",
        )
    

    Of course, you can go further and rewrite something that fit your needs :)