wutils.py
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Sat, 04 Jul 2009 08:15:48 +0200
changeset 4654 2eaebe77d66b
parent 4583 384117906219
permissions -rw-r--r--
Added tag ns-3.5 for changeset c975274c9707
gjc@3866
     1
import os
gjc@3866
     2
import os.path
gjc@3866
     3
import sys
gjc@3866
     4
import pproc as subprocess
gjc@3866
     5
import shlex
gjc@4064
     6
gjc@4064
     7
# WAF modules
gjc@3866
     8
import ccroot
gjc@4064
     9
import Options
gjc@4064
    10
import Utils
gjc@4064
    11
import Logs
gjc@4064
    12
import TaskGen
gjc@4064
    13
import Build
gjc@4332
    14
import re
gjc@4064
    15
gjc@3866
    16
gjc@3866
    17
# these are set from the main wscript file
gjc@3866
    18
APPNAME=None
gjc@3866
    19
VERSION=None
gjc@4326
    20
bld=None
gjc@4064
    21
gjc@3866
    22
#
gjc@3866
    23
# The last part of the path name to use to find the regression traces tarball.
gjc@3866
    24
# path will be APPNAME + '-' + VERSION + REGRESSION_SUFFIX + TRACEBALL_SUFFIX,
gjc@3866
    25
# e.g., ns-3-dev-ref-traces.tar.bz2
gjc@3866
    26
#
gjc@3866
    27
TRACEBALL_SUFFIX = ".tar.bz2"
gjc@3866
    28
gjc@3866
    29
gjc@3866
    30
gjc@4119
    31
def get_command_template(env, arguments=()):
gjc@4332
    32
    cmd = Options.options.command_template or '%s'
gjc@3866
    33
    for arg in arguments:
gjc@3866
    34
        cmd = cmd + " " + arg
gjc@3866
    35
    return cmd
gjc@3866
    36
gjc@3866
    37
gjc@4108
    38
if hasattr(os.path, "relpath"):
gjc@4108
    39
    relpath = os.path.relpath # since Python 2.6
gjc@4108
    40
else:
gjc@4108
    41
    def relpath(path, start=os.path.curdir):
gjc@4108
    42
        """Return a relative version of a path"""
gjc@4108
    43
gjc@4108
    44
        if not path:
gjc@4108
    45
            raise ValueError("no path specified")
gjc@4108
    46
gjc@4108
    47
        start_list = os.path.abspath(start).split(os.path.sep)
gjc@4108
    48
        path_list = os.path.abspath(path).split(os.path.sep)
gjc@4108
    49
gjc@4108
    50
        # Work out how much of the filepath is shared by start and path.
gjc@4108
    51
        i = len(os.path.commonprefix([start_list, path_list]))
gjc@4108
    52
gjc@4108
    53
        rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
gjc@4108
    54
        if not rel_list:
gjc@4108
    55
            return os.path.curdir
gjc@4108
    56
        return os.path.join(*rel_list)
gjc@4108
    57
gjc@3866
    58
gjc@3866
    59
def find_program(program_name, env):
gjc@4064
    60
    launch_dir = os.path.abspath(Options.cwd_launch)
gjc@4108
    61
    top_dir = os.path.abspath(Options.launch_dir)
gjc@3866
    62
    found_programs = []
gjc@4326
    63
    for obj in bld.all_task_gen:
gjc@3866
    64
        if not getattr(obj, 'is_ns3_program', False):
gjc@3866
    65
            continue
gjc@3866
    66
gjc@3866
    67
        ## filter out programs not in the subtree starting at the launch dir
gjc@3866
    68
        if not (obj.path.abspath().startswith(launch_dir)
gjc@3866
    69
                or obj.path.abspath(env).startswith(launch_dir)):
gjc@3866
    70
            continue
gjc@3866
    71
        
gjc@4108
    72
        name1 = obj.target
gjc@4108
    73
        name2 = os.path.join(relpath(obj.path.abspath(), top_dir), obj.target)
gjc@4108
    74
        names = [name1, name2]
gjc@4108
    75
        found_programs.extend(names)
gjc@4108
    76
        if program_name in names:
gjc@3866
    77
            return obj
gjc@3866
    78
    raise ValueError("program '%s' not found; available programs are: %r"
gjc@3866
    79
                     % (program_name, found_programs))
gjc@3866
    80
gjc@3866
    81
def get_proc_env(os_env=None):
gjc@4326
    82
    env = bld.env
gjc@3866
    83
    if sys.platform == 'linux2':
gjc@3866
    84
        pathvar = 'LD_LIBRARY_PATH'
gjc@3866
    85
    elif sys.platform == 'darwin':
gjc@3866
    86
        pathvar = 'DYLD_LIBRARY_PATH'
gjc@3866
    87
    elif sys.platform == 'win32':
gjc@3866
    88
        pathvar = 'PATH'
gjc@3866
    89
    elif sys.platform == 'cygwin':
gjc@3866
    90
        pathvar = 'PATH'
gjc@3866
    91
    elif sys.platform.startswith('freebsd'):
gjc@3866
    92
        pathvar = 'LD_LIBRARY_PATH'
gjc@3866
    93
    else:
gjc@4064
    94
        Logs.warn(("Don't know how to configure "
gjc@3866
    95
                        "dynamic library path for the platform %r;"
gjc@3866
    96
                        " assuming it's LD_LIBRARY_PATH.") % (sys.platform,))
gjc@3866
    97
        pathvar = 'LD_LIBRARY_PATH'        
gjc@3866
    98
gjc@3866
    99
    proc_env = dict(os.environ)
gjc@3866
   100
    if os_env is not None:
gjc@3866
   101
        proc_env.update(os_env)
gjc@3866
   102
gjc@3866
   103
    if pathvar is not None:
gjc@3866
   104
        if pathvar in proc_env:
gjc@3866
   105
            proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH']) + [proc_env[pathvar]])
gjc@3866
   106
        else:
gjc@3866
   107
            proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH']))
gjc@3866
   108
gjc@4326
   109
    pymoddir = bld.path.find_dir('bindings/python').abspath(env)
gjc@3866
   110
    if 'PYTHONPATH' in proc_env:
gjc@3866
   111
        proc_env['PYTHONPATH'] = os.pathsep.join([pymoddir] + [proc_env['PYTHONPATH']])
gjc@3866
   112
    else:
gjc@3866
   113
        proc_env['PYTHONPATH'] = pymoddir
gjc@3866
   114
gjc@3866
   115
    return proc_env
gjc@3866
   116
gjc@4388
   117
def run_argv(argv, env, os_env=None, cwd=None, force_no_valgrind=False):
gjc@3866
   118
    proc_env = get_proc_env(os_env)
gjc@4388
   119
    if Options.options.valgrind and not force_no_valgrind:
gjc@4332
   120
        if Options.options.command_template:
gjc@4332
   121
            raise Utils.WafError("Options --command-template and --valgrind are conflicting")
gjc@4332
   122
        if not env['VALGRIND']:
gjc@4332
   123
            raise Utils.WafError("valgrind is not installed")
gjc@4332
   124
        argv = [env['VALGRIND'], "--leak-check=full", "--error-exitcode=1"] + argv
gjc@4332
   125
        proc = subprocess.Popen(argv, env=proc_env, cwd=cwd, stderr=subprocess.PIPE)
gjc@4332
   126
        reg = re.compile ('definitely lost: ([^ ]+) bytes')
gjc@4332
   127
        error = False
gjc@4332
   128
        for line in proc.stderr:
gjc@4332
   129
            sys.stderr.write(line)
gjc@4332
   130
            result = reg.search(line)
gjc@4332
   131
            if result is None:
gjc@4332
   132
                continue
gjc@4332
   133
            if result.group(1) != "0":
gjc@4332
   134
                error = True
gjc@4332
   135
        retval = proc.wait()
gjc@4332
   136
        if retval == 0 and error:
gjc@4332
   137
            retval = 1
gjc@4332
   138
    else:
gjc@4583
   139
        try:
gjc@4583
   140
            WindowsError
gjc@4583
   141
        except NameError:
gjc@4583
   142
            retval = subprocess.Popen(argv, env=proc_env, cwd=cwd).wait()
gjc@4583
   143
        else:
gjc@4583
   144
            try:
gjc@4583
   145
                retval = subprocess.Popen(argv, env=proc_env, cwd=cwd).wait()
gjc@4583
   146
            except WindowsError, ex:
gjc@4583
   147
                raise Utils.WafError("Command %s raised exception %s" % (argv, ex))
gjc@3866
   148
    if retval:
gjc@4064
   149
        raise Utils.WafError("Command %s exited with code %i" % (argv, retval))
gjc@3866
   150
    return retval
gjc@3866
   151
gjc@3933
   152
def get_run_program(program_string, command_template=None):
gjc@3866
   153
    """
gjc@3933
   154
    Return the program name and argv of the process that would be executed by
gjc@3933
   155
    run_program(program_string, command_template).
gjc@3866
   156
    """
gjc@3933
   157
    #print "get_run_program_argv(program_string=%r, command_template=%r)" % (program_string, command_template)
gjc@4326
   158
    env = bld.env
gjc@3866
   159
gjc@3866
   160
    if command_template in (None, '%s'):
gjc@3866
   161
        argv = shlex.split(program_string)
gjc@4584
   162
        #print "%r ==shlex.split==> %r" % (program_string, argv)
gjc@3866
   163
        program_name = argv[0]
gjc@3866
   164
gjc@3866
   165
        try:
gjc@3866
   166
            program_obj = find_program(program_name, env)
gjc@3866
   167
        except ValueError, ex:
gjc@4064
   168
            raise Utils.WafError(str(ex))
gjc@3866
   169
gjc@4064
   170
        program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj))
gjc@4064
   171
        #try:
gjc@4064
   172
        #    program_node = program_obj.path.find_build(ccroot.get_target_name(program_obj))
gjc@4064
   173
        #except AttributeError:
gjc@4064
   174
        #    raise Utils.WafError("%s does not appear to be a program" % (program_name,))
gjc@3866
   175
gjc@3866
   176
        execvec = [program_node.abspath(env)] + argv[1:]
gjc@3866
   177
gjc@3866
   178
    else:
gjc@3866
   179
gjc@3866
   180
        program_name = program_string
gjc@3866
   181
        try:
gjc@3866
   182
            program_obj = find_program(program_name, env)
gjc@3866
   183
        except ValueError, ex:
gjc@4064
   184
            raise Utils.WafError(str(ex))
gjc@4064
   185
gjc@4064
   186
        program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj))
gjc@4064
   187
        #try:
gjc@4064
   188
        #    program_node = program_obj.path.find_build(ccroot.get_target_name(program_obj))
gjc@4064
   189
        #except AttributeError:
gjc@4064
   190
        #    raise Utils.WafError("%s does not appear to be a program" % (program_name,))
gjc@3866
   191
gjc@4584
   192
        tmpl = command_template % (program_node.abspath(env),)
gjc@4584
   193
        execvec = shlex.split(tmpl.replace('\\', '\\\\'))
gjc@4584
   194
        #print "%r ==shlex.split==> %r" % (command_template % (program_node.abspath(env),), execvec)
gjc@3933
   195
    return program_name, execvec
gjc@3866
   196
gjc@4332
   197
def run_program(program_string, env, command_template=None, cwd=None):
gjc@3933
   198
    """
gjc@3933
   199
    if command_template is not None, then program_string == program
gjc@3933
   200
    name and argv is given by command_template with %s replaced by the
gjc@3933
   201
    full path to the program.  Else, program_string is interpreted as
gjc@3933
   202
    a shell command with first name being the program name.
gjc@3933
   203
    """
gjc@3933
   204
    dummy_program_name, execvec = get_run_program(program_string, command_template)
gjc@4110
   205
    if cwd is None:
gjc@4110
   206
        if (Options.options.cwd_launch):
gjc@4110
   207
            cwd = Options.options.cwd_launch
gjc@4110
   208
        else:
gjc@4110
   209
            cwd = Options.cwd_launch
gjc@4332
   210
    return run_argv(execvec, env, cwd=cwd)
gjc@3866
   211
gjc@3866
   212
gjc@3866
   213
gjc@4332
   214
def run_python_program(program_string, env):
gjc@4326
   215
    env = bld.env
gjc@3866
   216
    execvec = shlex.split(program_string)
gjc@4137
   217
    if (Options.options.cwd_launch):
gjc@4137
   218
        cwd = Options.options.cwd_launch
gjc@4137
   219
    else:
gjc@4137
   220
        cwd = Options.cwd_launch
gjc@4332
   221
    return run_argv([env['PYTHON']] + execvec, env, cwd=cwd)
gjc@3866
   222
gjc@3866
   223