Question

I'm experimenting on converting a makefile from another buildsystem to waf.

I'm trying to direct waf to the directory containing the necessary dlls.

However, when running waf configure:

Checking for library libiconv2           : not found

It can't find the required library.

Directory stucture:

project/
| build/
| inc/
| | XGetopt.h
| | common.h
| | define.h
| | libpst.h
| | libstrfunc.h
| | lzfu.h
| | msg.h
| | timeconv.h
| | vbuf.h
| libs/
| | libiconv2.dll
| | regex2.dll
| src/
| | XGetopt.c
| | debug.c
| | dumpblocks.c
| | getidblock.c
| | libpst.c
| | libstrfunc.c
| | lspst.c
| | lzfu.c
| | readpst.c
| | timeconv.c
| | vbuf.c
| | deltasearch.cpp
| | msg.cpp
| | nick2ldif.cpp
| | pst2dii.cpp
| | pst2ldif.cpp
| | wscript_build
| waf-1.7.10
| wscript

top-level wscript:

#! /usr/bin/env python

VERSION = "0.1"
APPNAME = "readpst"

top = "." # The topmost directory of the waf project
out = "build/temp" # The build directory of the waf project

import os
from waflib import Build
from waflib import ConfigSet
from waflib import Logs

# Variant memory variables
var_path = out + "/variant.txt" # The variant memory file path
default_variant = "debug" # The default if no variant is stored
stored_variant = ""

def options(opt):
    '''
    A script hook function that defines addtional switch options for the build.
    '''
    opt.load("compiler_cxx")

def configure(cfg):
    '''
    A script hook function that configures the build environment.
    '''
    cfg.load("compiler_cxx")
    cfg.find_program("strip")
    cfg.env.PREFIX = "."
    cfg.env.DEFINES = ["WAF=1"]
    cfg.env.FEATURES = [] # Additional features
    cfg.env.LIBPATH = [os.path.join(os.getcwd(), "libs")]
    print cfg.env.LIBPATH
    cfg.define("VERSION", VERSION)
    base_env = cfg.env

    # Compiler checks
    cfg.check_large_file(mandatory = False)
    cfg.check_inline()

    # Check for the existance and function of specific headers
    cfg.check(header_name = "stdint.h")
    cfg.check(header_name = "stdio.h")
    cfg.check(compiler="cxx", uselib_store="LIBICONV2", mandatory=True, lib="libiconv2")

    # Define the debug build environment
    cfg.setenv("debug", env = base_env.derive())
    cfg.env.CFLAGS = ["-g"]
    cfg.define("DEBUG", 1)
    cfg.write_config_header("/debug/inc/config.h")

    # Define the release build environment
    cfg.setenv("release", env = base_env.derive())
    cfg.env.CFLAGS = ["-O2"]
    cfg.env.FEATURES = ["strip"]
    cfg.define("RELEASE", 1)
    cfg.write_config_header("/release/inc/config.h")

def pre(ctx):
    '''
    A callback for before build task start.
    '''
        print "Starting %sbuild" % (("%s " % ctx.variant) if(ctx.variant) else "")
        if ctx.cmd == "install":
        print "Installing"

def post(ctx):
    '''
    A callback for after build task finish.
    '''
    global var_path
        print "Finished %sbuild" % (("%s " % ctx.variant) if(ctx.variant) else "")
    env = ConfigSet.ConfigSet()
    env.stored_variant = ctx.variant
    env.store(var_path)

def build(bld):
    '''
    A script hook function that specifies the build behaviour.
    '''
    bld.add_pre_fun(pre)
    bld.add_post_fun(post)

    bld.recurse\
    (
        [
            "src"
        ]
    )
    if bld.cmd != "clean":
        bld.logger = Logs.make_logger("test.log", "build") # just to get a clean output

def dist(ctx):
    '''
    A script hook function that specifies the packaging behaviour.
    '''
    ctx.base_name = "_".join([APPNAME, VERSION])
    ctx.algo = "zip"
    file_ex_patterns = \
    [
        out + "/**",
        "**/.waf-1*",
        "**/*~",
        "**/*.pyc",
        "**/*.swp",
        "**/.lock-w*"
    ]
    file_in_patterns = \
    [
        "**/wscript*",
        "**/*.h",
        "**/*.c",
        "**/*.cpp",
        "**/*.txt",
    ]
    ctx.files = ctx.path.ant_glob(incl = file_in_patterns, excl = file_ex_patterns)

def set_variant():
    '''
    A function that facilitates dynamic changing of the Context classes variant member.
    It retrieves the stored variant, if existant, otherwise the default.
    '''
    global default_variant
    global stored_variant
    global var_path
    env = ConfigSet.ConfigSet()
    try:
        env.load(var_path)
    except:
        stored_variant = default_variant
    else:
        if(env.stored_variant):
            stored_variant = env.stored_variant
            print "Resuming %s variant" % stored_variant
        else:
            stored_variant = default_variant

def get_variant():
    '''
    A function that facilitates dynamic changing of the Context classes variant member.
    It sets the variant, if undefined, and returns.
    '''
    global stored_variant
    if(not stored_variant):
        set_variant()
    return stored_variant

class release(Build.BuildContext):
    '''
    A class that provides the release build.
    '''
    cmd = "release"
    variant = "release" 

class debug(Build.BuildContext):
    '''
    A class that provides the debug build.
    '''
    cmd = "debug"
    variant = "debug"

class default_build(Build.BuildContext):
    '''
    A class that provides the default variant build.
    This is set to debug.
    '''
    variant = "debug"

class default_clean(Build.CleanContext):
    '''
    A class that provides the stored variant build clean.
    '''
    @property
    def variant(self):
        return get_variant()

class default_install(Build.InstallContext):
    '''
    A class that provides the stored variant build install.
    '''
    @property
    def variant(self):
        return get_variant()

class default_uninstall(Build.UninstallContext):
    '''
    A class that provides the stored variant build uninstall.
    '''
    @property
    def variant(self):
        return get_variant()

# Addtional features
from waflib import Task, TaskGen
class strip(Task.Task):
    run_str = "${STRIP} ${SRC}"
    color   = "BLUE"

@TaskGen.feature("strip")
@TaskGen.after("apply_link")
def add_strip_task(self):
    try:
        link_task = self.link_task
    except:
        return
    tsk = self.create_task("strip", self.link_task.outputs[0])
Was it helpful?

Solution 2

After some consideration, I realised I required further information. The default error information provided by waf seems to be about waf itself, rather than the wscripts or the project.

To rectify this, loggers need to be added. I added loggers to the configure and build functions.

configure logger:

cfg.logger = Logs.make_logger("configure_%s.log" % datetime.date.today().strftime("%Y_%m_%d"), "configure")

build logger:

bld.logger = Logs.make_logger("build_%s.log" % datetime.date.today().strftime("%Y_%m_%d"), "build")

Doing this lead me to that nature of the problems:

['C:\\MinGW64\\bin\\g++.exe', '-Wl,--enable-auto-import', '-Wl,--enable-auto-import', 'test.cpp.1.o', '-o', 'C:\\Users\\Administrator\\Downloads\\libpst-0.6.60\\clean\\build\\temp\\conf_check_5fe204eaa3b3bcb7a9f85e15cebb726e\\testbuild\\testprog.exe', '-Wl,-Bstatic', '-Wl,-Bdynamic', '-LC:\\Users\\Administrator\\Downloads\\libpst-0.6.60\\clean\\libs', '-llibiconv2']

err: c:/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.7.2/../../../../x86_64-w64-mingw32/bin/ld.exe: skipping incompatible C:\Users\Administrator\Downloads\libpst-0.6.60\clean\libs/libiconv2.dll when searching for -llibiconv2

The library path has been passed correctly to gcc, but the dll is 32bit whereas the gcc installation is 64bit and so it is incompatible.

top-level wscript:

#! /usr/bin/env python

VERSION = "0.1"
APPNAME = "readpst"

top = "." # The topmost directory of the waf project
out = "build/temp" # The build directory of the waf project

import os
import datetime
from waflib import Build
from waflib import ConfigSet
from waflib import Logs

# Variant memory variables
var_path = out + "/variant.txt" # The variant memory file path
default_variant = "debug" # The default if no variant is stored
stored_variant = ""

def options(opt):
    '''
    A script hook function that defines addtional switch options for the build.
    '''
    opt.load("compiler_c compiler_cxx")

def configure(cfg):
    '''
    A script hook function that configures the build environment.
    '''
    cfg.logger = Logs.make_logger("configure_%s.log" % datetime.date.today().strftime("%Y_%m_%d"), "configure")
    cfg.load("compiler_c compiler_cxx")
    cfg.find_program("strip")
    cfg.env.DEFINES = \
    [
        "WAF=1",
        "HAVE_CONFIG_H=1"
    ]
    cfg.env.FEATURES = [] # Additional features
    cfg.env.append_value("LIBPATH", os.path.join(os.getcwd(), "libs"))
    cfg.env.append_value("INCLUDES", os.path.join(os.getcwd(), "inc"))
    cfg.env.append_value("INCLUDES", os.path.join(os.getcwd(), "inc", "glib-2.0"))
    cfg.env.append_value("INCLUDES", os.path.join(os.getcwd(), "inc", "glib-2.0", "glib"))
    cfg.env.append_value("INCLUDES", os.path.join(os.getcwd(), "libs", "regex", "2.7", "regex-2.7-src", "src"))
    cfg.env.append_value("INCLUDES", os.path.join(os.getcwd(), "libs", "libiconv", "1.9.2", "libiconv-1.9.2-src", "include"))

    cfg.define("VERSION", VERSION)

    base_env = cfg.env

    # Compiler checks
    cfg.check_large_file(mandatory = False)
    cfg.check_inline()

    cfg.multicheck\
    (
        {"header_name" : "fcntl.h"},
        {"header_name" : "iostream"},
        {"header_name" : "list"},
        {"header_name" : "set"},
        {"header_name" : "string"},
        {"header_name" : "vector"},
        msg = "Checking for standard headers",
        mandatory = True
    )

    cfg.check(header_name = "glib.h", mandatory = False)
    cfg.multicheck\
    (
        {"header_name" : "gsf\\gsf-infile-stdio.h"},
        {"header_name" : "gsf\\gsf-infile.h"},
        {"header_name" : "gsf\\gsf-input-stdio.h"},
        {"header_name" : "gsf\\gsf-outfile-msole.h"},
        {"header_name" : "gsf\\gsf-outfile.h"},
        {"header_name" : "gsf\\gsf-output-stdio.h"},
        {"header_name" : "gsf\\gsf-utils.h"},
        msg = "Checking for gsf headers",
        mandatory = False
    )

    # Checking for headers expected in config.h
    cfg.check(header_name = "ctype.h",     define_name = "HAVE_CTYPE_H"    , mandatory = False)
    cfg.check(header_name = "dirent.h",    define_name = "HAVE_DIRENT_H"   , mandatory = False)
    cfg.check(header_name = "errno.h",     define_name = "HAVE_ERRNO_H"    , mandatory = False)
    cfg.check(header_name = "gd.h",        define_name = "HAVE_GD_H"       , mandatory = False)
    cfg.check(header_name = "iconv.h",     define_name = "HAVE_ICON"       , mandatory = False)
    cfg.check(header_name = "limits.h",    define_name = "HAVE_LIMITS_H"   , mandatory = False)
    cfg.check(header_name = "regex.h",     define_name = "HAVE_REGEX_H"    , mandatory = False)
    #cfg.check(header_name = "semaphore.h", define_name = "HAVE_SEMAPHORE_H", mandatory = False)
    cfg.check(header_name = "signal.h",    define_name = "HAVE_SIGNAL_H"   , mandatory = False)
    cfg.check(header_name = "string.h",    define_name = "HAVE_STRING_H"   , mandatory = False)
    cfg.check(header_name = "sys/shm.h",   define_name = "HAVE_SYS_SHM_H"  , mandatory = False)
    cfg.check(header_name = "sys/stat.h",  define_name = "HAVE_SYS_STAT_H" , mandatory = False)
    cfg.check(header_name = "sys/types.h", define_name = "HAVE_SYS_TYPES_H", mandatory = False)
    cfg.check(header_name = "sys/wait.h",  define_name = "HAVE_SYS_WAIT_H" , mandatory = False)
    cfg.check(header_name = "wchar.h",     define_name = "HAVE_WCHAR_H"    , mandatory = False)

    cfg.check(header_name = "define.h", mandatory = False)
    cfg.check(header_name = "lzfu.h", mandatory = False)
    cfg.check(header_name = "msg.h", mandatory = False)

    # Check for the existance and function of specific headers
    cfg.check_cxx(lib = "libiconv2", uselib_store = "LIBICONV2", mandatory = False)

    # Define the debug build environment
    cfg.setenv("debug", env = base_env.derive())
    cfg.env.append_value("CFLAGS", "-g")
    cfg.define("DEBUG", 1)
    cfg.write_config_header("/debug/inc/config.h")

    # Define the release build environment
    cfg.setenv("release", env = base_env.derive())
    cfg.env.append_value("CFLAGS", "-02")
    cfg.env.FEATURES = ["strip"]
    cfg.define("RELEASE", 1)
    cfg.write_config_header("/release/inc/config.h")

def pre(ctx):
    '''
    A callback for before build task start.
    '''
        print "Starting %sbuild" % (("%s " % ctx.variant) if(ctx.variant) else "")
        if ctx.cmd == "install":
        print "Installing"

def post(ctx):
    '''
    A callback for after build task finish.
    '''
    global var_path
        print "Finished %sbuild" % (("%s " % ctx.variant) if(ctx.variant) else "")
    env = ConfigSet.ConfigSet()
    env.stored_variant = ctx.variant
    env.store(var_path)

def build(bld):
    '''
    A script hook function that specifies the build behaviour.
    '''
    if bld.cmd != "clean":
        bld.logger = Logs.make_logger("build_%s.log" % datetime.date.today().strftime("%Y_%m_%d"), "build")
    bld.add_pre_fun(pre)
    bld.add_post_fun(post)

    bld.recurse\
    (
        [
            "src"
        ]
    )

def dist(ctx):
    '''
    A script hook function that specifies the packaging behaviour.
    '''
    ctx.base_name = "_".join([APPNAME, VERSION])
    ctx.algo = "zip"
    file_ex_patterns = \
    [
        out + "/**",
        "**/.waf-1*",
        "**/*~",
        "**/*.pyc",
        "**/*.swp",
        "**/.lock-w*"
    ]
    file_in_patterns = \
    [
        "**/wscript*",
        "**/*.h",
        "**/*.c",
        "**/*.cpp",
        "**/*.txt",
    ]
    ctx.files = ctx.path.ant_glob(incl = file_in_patterns, excl = file_ex_patterns)

def set_variant():
    '''
    A function that facilitates dynamic changing of the Context classes variant member.
    It retrieves the stored variant, if existant, otherwise the default.
    '''
    global default_variant
    global stored_variant
    global var_path
    env = ConfigSet.ConfigSet()
    try:
        env.load(var_path)
    except:
        stored_variant = default_variant
    else:
        if(env.stored_variant):
            stored_variant = env.stored_variant
            print "Resuming %s variant" % stored_variant
        else:
            stored_variant = default_variant

def get_variant():
    '''
    A function that facilitates dynamic changing of the Context classes variant member.
    It sets the variant, if undefined, and returns.
    '''
    global stored_variant
    if(not stored_variant):
        set_variant()
    return stored_variant

class release(Build.BuildContext):
    '''
    A class that provides the release build.
    '''
    cmd = "release"
    variant = "release" 

class debug(Build.BuildContext):
    '''
    A class that provides the debug build.
    '''
    cmd = "debug"
    variant = "debug"

class default_build(Build.BuildContext):
    '''
    A class that provides the default variant build.
    This is set to debug.
    '''
    variant = "debug"

class default_clean(Build.CleanContext):
    '''
    A class that provides the stored variant build clean.
    '''
    @property
    def variant(self):
        return get_variant()

class default_install(Build.InstallContext):
    '''
    A class that provides the stored variant build install.
    '''
    @property
    def variant(self):
        return get_variant()

class default_uninstall(Build.UninstallContext):
    '''
    A class that provides the stored variant build uninstall.
    '''
    @property
    def variant(self):
        return get_variant()

# Addtional features
from waflib import Task, TaskGen
class strip(Task.Task):
    run_str = "${STRIP} ${SRC}"
    color   = "BLUE"

@TaskGen.feature("strip")
@TaskGen.after("apply_link")
def add_strip_task(self):
    try:
        link_task = self.link_task
    except:
        return
    tsk = self.create_task("strip", self.link_task.outputs[0])

OTHER TIPS

You just lack the use variable setup, but this has to be fixed in your child-wscripts, i.e.

bld.program (...,
    libpath = ['/usr/lib', 'subpath'], #this has to be relative to the wscript it appears in! (or the root wscript, can not recall)
    ...,
    use = ['iconv2', 'regex2'] )

See section 9.1.2 of the waf book


Alternatively: (and probably the cleaner version)

cfg.check_cc(lib='iconv2', uselib_store="LIBICONV2", mandatory=True)

and then use uselib with

bld.program (...,
    libpath = ['/usr/lib', 'subpath'], #this has to be relative to the wscript it appears in! (or the root wscript, can not recall)
    ...,
    uselib = ['LIBICONV2', ...] )
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top