3

Dear WAF build system experts,

Let's suppose that you use the WAF build system to build a library fooLib and a program fooProg. Then, you want to check the program fooProg by a Python script fooProgTest that checks the output of fooProg.

Here is an minimum example for fooLib and fooProg:

$ cat fooLib/fooLib.cpp 
int foo()
{
    return 42;
}
$ cat fooProg/fooProg.cpp 
#include <iostream>

extern int foo();

int main()
{
    std::cout << foo() << std::endl;
    return 0;
}

In this example, it is my goal to to have a Python script that checks that fooProg outputs 42. Here comes my not so clean solution:

import os
from waflib.Tools import waf_unit_test


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


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

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

    bld(features= "cxx cxxshlib",
        target= "fooLib",
        source= "fooLib/fooLib.cpp")

    bld(features= "cxx cxxprogram",
        target= "fooProg/fooProg",
        source= "fooProg/fooProg.cpp",
        use= "fooLib")

    testEnv= os.environ.copy()
    testEnv["FOO_EXE"]= bld.path.find_or_declare("fooProg/fooProg").abspath()
    bld(features= "test_scripts",
        test_scripts_source= "fooProgTest/fooProgTest.py",
        test_scripts_template= "${PYTHON} ${SRC[0].abspath()}",
        test_scripts_paths= {
            "LD_LIBRARY_PATH": bld.bldnode.abspath()
        },
        test_scripts_env= testEnv
       ) 
cat fooProgTest/fooProgTest.py 
#!/usr/bin/env python

import os
import subprocess

assert subprocess.check_output("{}".format(
        os.environ["FOO_EXE"])).startswith("42")

My questions are below:

  • Does anyone of you know how to avoid setting LD_LIBRARY_PATH manually?
  • How to avoid setting the path of fooProg via the environment variable "FOO_EXE"?

Thank you very much!

M_Kulas
  • 53
  • 5

1 Answers1

0

Does anyone of you know how to avoid setting LD_LIBRARY_PATH manually?

You can specify the runtime search path for your executable. Assuming that the file fooLib.so is in the same directory as fooProg, the following change to your wscript should suffice:


    bld(features= "cxx cxxprogram",
        target= "fooProg/fooProg",
        source= "fooProg/fooProg.cpp",
        use= "fooLib",
        rpath= "$ORIGIN")

Which makes LD to take the directory, where the executable is stored, also into consideration, when searching for shared objects.

How to avoid setting the path of fooProg via the environment variable "FOO_EXE"?

With subprocess.check_output you can pass multiple arguments. I.e.


    subprocess.check_output([
        "your_executable_to_launch",
        "arg1",
        "arg2"
    ])

In your test script you would have to read the arguments either using sys.argv or argparse.


Extra:

Launching the interpreter to launch to launch your application seems a bit hacky. Instead, define a custom task (implement waflib.Task.Task), which then runs subprocess.check_output1.


1 AFAIK waf gives you a convenient method to launch processes, although I cannot remember its name.

Julian Kirsch
  • 539
  • 4
  • 17