1.1 --- a/doc/build.txt Fri Oct 23 16:22:56 2009 +0400
1.2 +++ b/doc/build.txt Fri Oct 23 16:23:38 2009 +0400
1.3 @@ -7,10 +7,10 @@
1.4
1.5 === Installing Waf ===
1.6
1.7 -The top-level ns-3 directory should contain a current waf script.
1.8 -
1.9 -Note: we're using a WAF version based on WAF 1.5.x. The source code
1.10 -can be retrieved from the followin URL:
1.11 +The top-level ns-3 directory should contain a current waf script, so
1.12 +there is no need to have WAF installed in the system. We are using
1.13 +some extensions to WAF, which can be found in the 'waf-tools'
1.14 +directory. The upstream location for these WAF extensions is:
1.15
1.16 https://code.launchpad.net/~gjc/waf/cmd
1.17
2.1 Binary file waf has changed
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/waf-tools/cflags.py Fri Oct 23 16:23:38 2009 +0400
3.3 @@ -0,0 +1,192 @@
3.4 +import Logs
3.5 +import Options
3.6 +import Utils
3.7 +
3.8 +
3.9 +class CompilerTraits(object):
3.10 + def get_warnings_flags(self, level):
3.11 + """get_warnings_flags(level) -> list of cflags"""
3.12 + raise NotImplementedError
3.13 +
3.14 + def get_optimization_flags(self, level):
3.15 + """get_optimization_flags(level) -> list of cflags"""
3.16 + raise NotImplementedError
3.17 +
3.18 + def get_debug_flags(self, level):
3.19 + """get_debug_flags(level) -> (list of cflags, list of cppdefines)"""
3.20 + raise NotImplementedError
3.21 +
3.22 +
3.23 +class GccTraits(CompilerTraits):
3.24 + def __init__(self):
3.25 + super(GccTraits, self).__init__()
3.26 + # cumulative list of warnings per level
3.27 + self.warnings_flags = [['-Wall'], ['-Werror'], ['-Wextra']]
3.28 +
3.29 + def get_warnings_flags(self, level):
3.30 + warnings = []
3.31 + for l in range(level):
3.32 + if l < len(self.warnings_flags):
3.33 + warnings.extend(self.warnings_flags[l])
3.34 + else:
3.35 + break
3.36 + return warnings
3.37 +
3.38 + def get_optimization_flags(self, level):
3.39 + if level == 0:
3.40 + return ['-O0']
3.41 + elif level == 1:
3.42 + return ['-O']
3.43 + elif level == 2:
3.44 + return ['-O2']
3.45 + elif level == 3:
3.46 + return ['-O3']
3.47 +
3.48 + def get_debug_flags(self, level):
3.49 + if level == 0:
3.50 + return (['-g0'], ['NDEBUG'])
3.51 + elif level == 1:
3.52 + return (['-g'], [])
3.53 + elif level >= 2:
3.54 + return (['-ggdb', '-g3'], ['_DEBUG'])
3.55 +
3.56 +
3.57 +class IccTraits(CompilerTraits):
3.58 + def __init__(self):
3.59 + super(IccTraits, self).__init__()
3.60 + # cumulative list of warnings per level
3.61 + # icc is _very_ verbose with -Wall, -Werror is barely achievable
3.62 + self.warnings_flags = [[], [], ['-Wall']]
3.63 +
3.64 + def get_warnings_flags(self, level):
3.65 + warnings = []
3.66 + for l in range(level):
3.67 + if l < len(self.warnings_flags):
3.68 + warnings.extend(self.warnings_flags[l])
3.69 + else:
3.70 + break
3.71 + return warnings
3.72 +
3.73 + def get_optimization_flags(self, level):
3.74 + if level == 0:
3.75 + return ['-O0']
3.76 + elif level == 1:
3.77 + return ['-O']
3.78 + elif level == 2:
3.79 + return ['-O2']
3.80 + elif level == 3:
3.81 + return ['-O3']
3.82 +
3.83 + def get_debug_flags(self, level):
3.84 + if level == 0:
3.85 + return (['-g0'], ['NDEBUG'])
3.86 + elif level == 1:
3.87 + return (['-g'], [])
3.88 + elif level >= 2:
3.89 + return (['-ggdb', '-g3'], ['_DEBUG'])
3.90 +
3.91 +
3.92 +
3.93 +class MsvcTraits(CompilerTraits):
3.94 + def __init__(self):
3.95 + super(MsvcTraits, self).__init__()
3.96 + # cumulative list of warnings per level
3.97 + self.warnings_flags = [['/W2'], ['/WX'], ['/Wall']]
3.98 +
3.99 + def get_warnings_flags(self, level):
3.100 + warnings = []
3.101 + for l in range(level):
3.102 + if l < len(self.warnings_flags):
3.103 + warnings.extend(self.warnings_flags[l])
3.104 + else:
3.105 + break
3.106 + return warnings
3.107 +
3.108 + def get_optimization_flags(self, level):
3.109 + if level == 0:
3.110 + return ['/Od']
3.111 + elif level == 1:
3.112 + return []
3.113 + elif level == 2:
3.114 + return ['/O2']
3.115 + elif level == 3:
3.116 + return ['/Ox']
3.117 +
3.118 + def get_debug_flags(self, level):
3.119 + if level == 0:
3.120 + return ([], ['NDEBUG'])
3.121 + elif level == 1:
3.122 + return (['/ZI', '/RTC1'], [])
3.123 + elif level >= 2:
3.124 + return (['/ZI', '/RTC1'], ['_DEBUG'])
3.125 +
3.126 +
3.127 +
3.128 +gcc = GccTraits()
3.129 +icc = IccTraits()
3.130 +msvc = MsvcTraits()
3.131 +
3.132 +# how to map env['COMPILER_CC'] or env['COMPILER_CXX'] into a traits object
3.133 +compiler_mapping = {
3.134 + 'gcc': gcc,
3.135 + 'g++': gcc,
3.136 + 'msvc': msvc,
3.137 + 'icc': icc,
3.138 + 'icpc': icc,
3.139 +}
3.140 +
3.141 +profiles = {
3.142 + # profile name: [optimization_level, warnings_level, debug_level]
3.143 + 'default': [2, 1, 1],
3.144 + 'debug': [0, 2, 3],
3.145 + 'release': [3, 1, 0],
3.146 + }
3.147 +
3.148 +default_profile = 'default'
3.149 +
3.150 +def set_options(opt):
3.151 + assert default_profile in profiles
3.152 + opt.add_option('-d', '--build-profile',
3.153 + action='store',
3.154 + default=default_profile,
3.155 + help=("Specify the build profile. "
3.156 + "Build profiles control the default compilation flags"
3.157 + " used for C/C++ programs, if CCFLAGS/CXXFLAGS are not"
3.158 + " set set in the environment. [Allowed Values: %s]"
3.159 + % ", ".join([repr(p) for p in profiles.keys()])),
3.160 + choices=profiles.keys(),
3.161 + dest='build_profile')
3.162 +
3.163 +def detect(conf):
3.164 + cc = conf.env['COMPILER_CC'] or None
3.165 + cxx = conf.env['COMPILER_CXX'] or None
3.166 + if not (cc or cxx):
3.167 + raise Utils.WafError("neither COMPILER_CC nor COMPILER_CXX are defined; "
3.168 + "maybe the compiler_cc or compiler_cxx tool has not been configured yet?")
3.169 +
3.170 + try:
3.171 + compiler = compiler_mapping[cc]
3.172 + except KeyError:
3.173 + try:
3.174 + compiler = compiler_mapping[cxx]
3.175 + except KeyError:
3.176 + Logs.warn("No compiler flags support for compiler %r or %r"
3.177 + % (cc, cxx))
3.178 + return
3.179 +
3.180 + opt_level, warn_level, dbg_level = profiles[Options.options.build_profile]
3.181 +
3.182 + optimizations = compiler.get_optimization_flags(opt_level)
3.183 + debug, debug_defs = compiler.get_debug_flags(dbg_level)
3.184 + warnings = compiler.get_warnings_flags(warn_level)
3.185 +
3.186 + if cc and not conf.env['CCFLAGS']:
3.187 + conf.env.append_value('CCFLAGS', optimizations)
3.188 + conf.env.append_value('CCFLAGS', debug)
3.189 + conf.env.append_value('CCFLAGS', warnings)
3.190 + conf.env.append_value('CCDEFINES', debug_defs)
3.191 + if cxx and not conf.env['CXXFLAGS']:
3.192 + conf.env.append_value('CXXFLAGS', optimizations)
3.193 + conf.env.append_value('CXXFLAGS', debug)
3.194 + conf.env.append_value('CXXFLAGS', warnings)
3.195 + conf.env.append_value('CXXDEFINES', debug_defs)
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/waf-tools/command.py Fri Oct 23 16:23:38 2009 +0400
4.3 @@ -0,0 +1,134 @@
4.4 +from TaskGen import feature, taskgen, before, task_gen
4.5 +import Node, Task, Utils, Build, pproc, Constants
4.6 +import Options
4.7 +
4.8 +import shellcmd
4.9 +shellcmd.subprocess = pproc # the WAF version of the subprocess module is supposedly less buggy
4.10 +
4.11 +from Logs import debug, error
4.12 +shellcmd.debug = debug
4.13 +
4.14 +import Task
4.15 +
4.16 +import re
4.17 +
4.18 +
4.19 +arg_rx = re.compile(r"(?P<dollar>\$\$)|(?P<subst>\$\{(?P<var>\w+)(?P<code>.*?)\})", re.M)
4.20 +
4.21 +class command_task(Task.Task):
4.22 + color = "BLUE"
4.23 + def __init__(self, env, generator):
4.24 + Task.Task.__init__(self, env, normal=1, generator=generator)
4.25 +
4.26 + def __str__(self):
4.27 + "string to display to the user"
4.28 + env = self.env
4.29 + src_str = ' '.join([a.nice_path(env) for a in self.inputs])
4.30 + tgt_str = ' '.join([a.nice_path(env) for a in self.outputs])
4.31 + if self.outputs:
4.32 + sep = ' -> '
4.33 + else:
4.34 + sep = ''
4.35 +
4.36 + pipeline = shellcmd.Pipeline()
4.37 + pipeline.parse(self.generator.command)
4.38 + cmd = pipeline.get_abbreviated_command()
4.39 +
4.40 + return 'command (%s): %s%s%s\n' % (cmd, src_str, sep, tgt_str)
4.41 +
4.42 + def _subst_arg(self, arg, direction, namespace):
4.43 + """
4.44 + @param arg: the command argument (or stdin/stdout/stderr) to substitute
4.45 + @param direction: direction of the argument: 'in', 'out', or None
4.46 + """
4.47 + def repl(match):
4.48 + if match.group('dollar'):
4.49 + return "$"
4.50 + elif match.group('subst'):
4.51 + var = match.group('var')
4.52 + code = match.group('code')
4.53 + result = eval(var+code, namespace)
4.54 + if isinstance(result, Node.Node):
4.55 + if var == 'TGT':
4.56 + return result.bldpath(self.env)
4.57 + elif var == 'SRC':
4.58 + return result.srcpath(self.env)
4.59 + else:
4.60 + raise ValueError("Bad subst variable %r" % var)
4.61 + elif result is self.inputs:
4.62 + if len(self.inputs) == 1:
4.63 + return result[0].srcpath(self.env)
4.64 + else:
4.65 + raise ValueError("${SRC} requested but have multiple sources; which one?")
4.66 + elif result is self.outputs:
4.67 + if len(self.outputs) == 1:
4.68 + return result[0].bldpath(self.env)
4.69 + else:
4.70 + raise ValueError("${TGT} requested but have multiple targets; which one?")
4.71 + else:
4.72 + return result
4.73 + return None
4.74 +
4.75 + return arg_rx.sub(repl, arg)
4.76 +
4.77 + def run(self):
4.78 + pipeline = shellcmd.Pipeline()
4.79 + pipeline.parse(self.generator.command)
4.80 + namespace = self.env.get_merged_dict()
4.81 + if self.generator.variables is not None:
4.82 + namespace.update(self.generator.variables)
4.83 + namespace.update(env=self.env, SRC=self.inputs, TGT=self.outputs)
4.84 + for cmd in pipeline.pipeline:
4.85 + if isinstance(cmd, shellcmd.Command):
4.86 + if isinstance(cmd.stdin, basestring):
4.87 + cmd.stdin = self._subst_arg(cmd.stdin, 'in', namespace)
4.88 + if isinstance(cmd.stdout, basestring):
4.89 + cmd.stdout = self._subst_arg(cmd.stdout, 'out', namespace)
4.90 + if isinstance(cmd.stderr, basestring):
4.91 + cmd.stderr = self._subst_arg(cmd.stderr, 'out', namespace)
4.92 + for argI in xrange(len(cmd.argv)):
4.93 + cmd.argv[argI] = self._subst_arg(cmd.argv[argI], None, namespace)
4.94 + if cmd.env_vars is not None:
4.95 + env_vars = dict()
4.96 + for name, value in cmd.env_vars.iteritems():
4.97 + env_vars[name] = self._subst_arg(value, None, namespace)
4.98 + cmd.env_vars = env_vars
4.99 + elif isinstance(cmd, shellcmd.Chdir):
4.100 + cmd.dir = self._subst_arg(cmd.dir, None, namespace)
4.101 +
4.102 + return pipeline.run(verbose=(Options.options.verbose > 0))
4.103 +
4.104 +@taskgen
4.105 +@feature('command')
4.106 +def init_command(self):
4.107 + Utils.def_attrs(self,
4.108 + # other variables that can be used in the command: ${VARIABLE}
4.109 + variables = None)
4.110 +
4.111 +
4.112 +
4.113 +@taskgen
4.114 +@feature('command')
4.115 +@before('apply_core')
4.116 +def apply_command(self):
4.117 + self.meths.remove('apply_core')
4.118 + # create the task
4.119 + task = self.create_task('command')
4.120 + setattr(task, "dep_vars", getattr(self, "dep_vars", None))
4.121 + # process the sources
4.122 + inputs = []
4.123 + for src in self.to_list(self.source):
4.124 + node = self.path.find_resource(src)
4.125 + if node is None:
4.126 + raise Utils.WafError("source %s not found" % src)
4.127 + inputs.append(node)
4.128 + task.set_inputs(inputs)
4.129 + task.set_outputs([self.path.find_or_declare(tgt) for tgt in self.to_list(self.target)])
4.130 + #Task.file_deps = Task.extract_deps
4.131 +
4.132 +
4.133 +
4.134 +class command_taskgen(task_gen):
4.135 + def __init__(self, *k, **kw):
4.136 + task_gen.__init__(self, *k, **kw)
4.137 + self.features.append('command')
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/waf-tools/pkgconfig.py Fri Oct 23 16:23:38 2009 +0400
5.3 @@ -0,0 +1,71 @@
5.4 +# -*- mode: python; encoding: utf-8 -*-
5.5 +# Gustavo Carneiro (gjamc) 2008
5.6 +
5.7 +import Options
5.8 +import Configure
5.9 +import pproc as subprocess
5.10 +import config_c
5.11 +
5.12 +def detect(conf):
5.13 + pkg_config = conf.find_program('pkg-config', var='PKG_CONFIG')
5.14 + if not pkg_config: return
5.15 +
5.16 +@Configure.conf
5.17 +def pkg_check_modules(conf, uselib_name, expression, mandatory=True):
5.18 + pkg_config = conf.env['PKG_CONFIG']
5.19 + if not pkg_config:
5.20 + if mandatory:
5.21 + conf.fatal("pkg-config is not available")
5.22 + else:
5.23 + return False
5.24 +
5.25 + argv = [pkg_config, '--cflags', '--libs', expression]
5.26 + cmd = subprocess.Popen(argv, stdout=subprocess.PIPE)
5.27 + out, dummy = cmd.communicate()
5.28 + retval = cmd.wait()
5.29 +
5.30 + msg_checking = ("pkg-config flags for %s" % (uselib_name,))
5.31 + if Options.options.verbose:
5.32 + if retval == 0:
5.33 + conf.check_message_custom(msg_checking,
5.34 + ('(%s)' % expression), out)
5.35 + else:
5.36 + conf.check_message(msg_checking, ('(%s)' % expression), False)
5.37 + else:
5.38 + conf.check_message(msg_checking, '', (retval == 0), '')
5.39 + conf.log.write('%r: %r (exit code %i)\n' % (argv, out, retval))
5.40 +
5.41 + if retval == 0:
5.42 +
5.43 + config_c.parse_flags(out, uselib_name, conf.env)
5.44 + conf.env[uselib_name] = True
5.45 + return True
5.46 +
5.47 + else:
5.48 +
5.49 + conf.env[uselib_name] = False
5.50 + if mandatory:
5.51 + raise Configure.ConfigurationError('pkg-config check failed')
5.52 + else:
5.53 + return False
5.54 +
5.55 +@Configure.conf
5.56 +def pkg_check_module_variable(conf, module, variable):
5.57 + pkg_config = conf.env['PKG_CONFIG']
5.58 + if not pkg_config:
5.59 + conf.fatal("pkg-config is not available")
5.60 +
5.61 + argv = [pkg_config, '--variable', variable, module]
5.62 + cmd = subprocess.Popen(argv, stdout=subprocess.PIPE)
5.63 + out, dummy = cmd.communicate()
5.64 + retval = cmd.wait()
5.65 + out = out.rstrip() # strip the trailing newline
5.66 +
5.67 + msg_checking = ("pkg-config variable %r in %s" % (variable, module,))
5.68 + conf.check_message_custom(msg_checking, '', out)
5.69 + conf.log.write('%r: %r (exit code %i)\n' % (argv, out, retval))
5.70 +
5.71 + if retval == 0:
5.72 + return out
5.73 + else:
5.74 + raise Configure.ConfigurationError('pkg-config check failed')
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/waf-tools/shellcmd.py Fri Oct 23 16:23:38 2009 +0400
6.3 @@ -0,0 +1,345 @@
6.4 +# Copyright (C) 2008 Gustavo J. A. M. Carneiro <gjcarneiro@gmail.com>
6.5 +
6.6 +# This program is free software; you can redistribute it and/or modify
6.7 +# it under the terms of the GNU General Public License as published by
6.8 +# the Free Software Foundation; either version 2 of the License, or
6.9 +# (at your option) any later version.
6.10 +
6.11 +# This program is distributed in the hope that it will be useful,
6.12 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
6.13 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6.14 +# GNU General Public License for more details.
6.15 +
6.16 +# You should have received a copy of the GNU General Public License
6.17 +# along with this program; if not, write to the Free Software
6.18 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
6.19 +
6.20 +import shlex
6.21 +import subprocess
6.22 +import sys
6.23 +import re
6.24 +import os
6.25 +
6.26 +env_var_rx = re.compile(r"^([a-zA-Z0-9_]+)=(\S+)$")
6.27 +
6.28 +def debug(message):
6.29 + print >> sys.stderr, message
6.30 +
6.31 +
6.32 +if sys.platform == 'win32':
6.33 + dev_null = open("NUL:", "w")
6.34 +else:
6.35 + dev_null = open("/dev/null", "w")
6.36 +
6.37 +def _open_out_file(filename):
6.38 + if filename in ['NUL:', '/dev/null']:
6.39 + return dev_null
6.40 + else:
6.41 + return open(filename, 'wb')
6.42 +
6.43 +
6.44 +class Node(object):
6.45 + pass
6.46 +
6.47 +class Op(Node):
6.48 + pass
6.49 +
6.50 +class Pipe(Op):
6.51 + pass
6.52 +
6.53 +class And(Op):
6.54 + pass
6.55 +
6.56 +class Or(Op):
6.57 + pass
6.58 +
6.59 +class Command(Node):
6.60 + class PIPE(object):
6.61 + pass # PIPE is a constant
6.62 + class STDOUT(object):
6.63 + pass # PIPE is a constant
6.64 +
6.65 + def __init__(self, name):
6.66 + super(Command, self).__init__()
6.67 + self.name = name # command name
6.68 + self.argv = [name] # command argv
6.69 + self.stdin = None
6.70 + self.stdout = None
6.71 + self.stderr = None
6.72 + self.env_vars = None
6.73 +
6.74 + def __repr__(self):
6.75 + return "Command(%r, argv=%r, stdin=%r, stdout=%r, stderr=%r)" \
6.76 + % (self.name, self.argv, self.stdin, self.stdout, self.stderr)
6.77 +
6.78 +class Chdir(Node):
6.79 + def __init__(self):
6.80 + super(Chdir, self).__init__()
6.81 + self.dir = None
6.82 +
6.83 + def __repr__(self):
6.84 + return "Chdir(%r)" \
6.85 + % (self.dir)
6.86 +
6.87 +class Pipeline(object):
6.88 + def __init__(self):
6.89 + self.current_command = None
6.90 + self.pipeline = []
6.91 +
6.92 + def _commit_command(self):
6.93 + assert self.current_command is not None
6.94 + self.pipeline.append(self.current_command)
6.95 + self.current_command = None
6.96 +
6.97 + def get_abbreviated_command(self):
6.98 + l = []
6.99 + for node in self.pipeline:
6.100 + if isinstance(node, Command):
6.101 + l.append(node.name)
6.102 + if isinstance(node, Chdir):
6.103 + l.append('cd %s' % node.dir)
6.104 + elif isinstance(node, Pipe):
6.105 + l.append('|')
6.106 + elif isinstance(node, And):
6.107 + l.append('&&')
6.108 + elif isinstance(node, And):
6.109 + l.append('||')
6.110 + return ' '.join(l)
6.111 +
6.112 + def parse(self, command):
6.113 + self.current_command = None
6.114 + self.pipeline = []
6.115 +
6.116 + if isinstance(command, list):
6.117 + tokens = list(command)
6.118 + else:
6.119 + tokens = shlex.split(command)
6.120 + debug("command: shlex: %r" % (tokens,))
6.121 +
6.122 + BEGIN, COMMAND, CHDIR, STDERR, STDOUT, STDIN = range(6)
6.123 + state = BEGIN
6.124 + self.current_command = None
6.125 + env_vars = dict()
6.126 +
6.127 + while tokens:
6.128 + token = tokens.pop(0)
6.129 + if state == BEGIN:
6.130 + env_var_match = env_var_rx.match(token)
6.131 + if env_var_match is not None:
6.132 + env_vars[env_var_match.group(1)] = env_var_match.group(2)
6.133 + else:
6.134 + assert self.current_command is None
6.135 + if token == 'cd':
6.136 + self.current_command = Chdir()
6.137 + assert not env_vars
6.138 + state = CHDIR
6.139 + else:
6.140 + self.current_command = Command(token)
6.141 + if env_vars:
6.142 + self.current_command.env_vars = env_vars
6.143 + env_vars = dict()
6.144 + state = COMMAND
6.145 + elif state == COMMAND:
6.146 + if token == '>':
6.147 + state = STDOUT
6.148 + elif token == '2>':
6.149 + state = STDERR
6.150 + elif token == '2>&1':
6.151 + assert self.current_command.stderr is None
6.152 + self.current_command.stderr = Command.STDOUT
6.153 + elif token == '<':
6.154 + state = STDIN
6.155 + elif token == '|':
6.156 + assert self.current_command.stdout is None
6.157 + self.current_command.stdout = Command.PIPE
6.158 + self._commit_command()
6.159 + self.pipeline.append(Pipe())
6.160 + state = BEGIN
6.161 + elif token == '&&':
6.162 + self._commit_command()
6.163 + self.pipeline.append(And())
6.164 + state = BEGIN
6.165 + elif token == '||':
6.166 + self._commit_command()
6.167 + self.pipeline.append(Or())
6.168 + state = BEGIN
6.169 + else:
6.170 + self.current_command.argv.append(token)
6.171 + elif state == CHDIR:
6.172 + if token == '&&':
6.173 + self._commit_command()
6.174 + self.pipeline.append(And())
6.175 + state = BEGIN
6.176 + else:
6.177 + assert self.current_command.dir is None
6.178 + self.current_command.dir = token
6.179 + elif state == STDOUT:
6.180 + assert self.current_command.stdout is None
6.181 + self.current_command.stdout = token
6.182 + state = COMMAND
6.183 + elif state == STDERR:
6.184 + assert self.current_command.stderr is None
6.185 + self.current_command.stderr = token
6.186 + state = COMMAND
6.187 + elif state == STDIN:
6.188 + assert self.current_command.stdin is None
6.189 + self.current_command.stdin = token
6.190 + state = COMMAND
6.191 + self._commit_command()
6.192 + return self.pipeline
6.193 +
6.194 + def _exec_piped_commands(self, commands):
6.195 + retvals = []
6.196 + for cmd in commands:
6.197 + retvals.append(cmd.wait())
6.198 + retval = 0
6.199 + for r in retvals:
6.200 + if r:
6.201 + retval = retvals[-1]
6.202 + break
6.203 + return retval
6.204 +
6.205 + def run(self, verbose=False):
6.206 + pipeline = list(self.pipeline)
6.207 + files_to_close = []
6.208 + piped_commands = []
6.209 + piped_commands_display = []
6.210 + BEGIN, PIPE = range(2)
6.211 + state = BEGIN
6.212 + cwd = '.'
6.213 + while pipeline:
6.214 + node = pipeline.pop(0)
6.215 +
6.216 + if isinstance(node, Chdir):
6.217 + next_op = pipeline.pop(0)
6.218 + assert isinstance(next_op, And)
6.219 + cwd = os.path.join(cwd, node.dir)
6.220 + if verbose:
6.221 + piped_commands_display.append("cd %s &&" % node.dir)
6.222 + continue
6.223 +
6.224 + assert isinstance(node, (Command, Chdir))
6.225 + cmd = node
6.226 + if verbose:
6.227 + if cmd.env_vars:
6.228 + env_vars_str = ' '.join(['%s=%s' % (key, val) for key, val in cmd.env_vars.iteritems()])
6.229 + piped_commands_display.append("%s %s" % (env_vars_str, ' '.join(cmd.argv)))
6.230 + else:
6.231 + piped_commands_display.append(' '.join(cmd.argv))
6.232 +
6.233 + if state == PIPE:
6.234 + stdin = piped_commands[-1].stdout
6.235 + elif cmd.stdin is not None:
6.236 + stdin = open(cmd.stdin, "r")
6.237 + if verbose:
6.238 + piped_commands_display.append('< %s' % cmd.stdin)
6.239 + files_to_close.append(stdin)
6.240 + else:
6.241 + stdin = None
6.242 +
6.243 + if cmd.stdout is None:
6.244 + stdout = None
6.245 + elif cmd.stdout is Command.PIPE:
6.246 + stdout = subprocess.PIPE
6.247 + else:
6.248 + stdout = _open_out_file(cmd.stdout)
6.249 + files_to_close.append(stdout)
6.250 + if verbose:
6.251 + piped_commands_display.append('> %s' % cmd.stdout)
6.252 +
6.253 + if cmd.stderr is None:
6.254 + stderr = None
6.255 + elif cmd.stderr is Command.PIPE:
6.256 + stderr = subprocess.PIPE
6.257 + elif cmd.stderr is Command.STDOUT:
6.258 + stderr = subprocess.STDOUT
6.259 + if verbose:
6.260 + piped_commands_display.append('2>&1')
6.261 + else:
6.262 + stderr = _open_out_file(cmd.stderr)
6.263 + files_to_close.append(stderr)
6.264 + if verbose:
6.265 + piped_commands_display.append('2> %s' % cmd.stderr)
6.266 +
6.267 + if cmd.env_vars:
6.268 + env = dict(os.environ)
6.269 + env.update(cmd.env_vars)
6.270 + else:
6.271 + env = None
6.272 +
6.273 + if cwd == '.':
6.274 + proc_cwd = None
6.275 + else:
6.276 + proc_cwd = cwd
6.277 +
6.278 + debug("command: subprocess.Popen(argv=%r, stdin=%r, stdout=%r, stderr=%r, env_vars=%r, cwd=%r)"
6.279 + % (cmd.argv, stdin, stdout, stderr, cmd.env_vars, proc_cwd))
6.280 + proc = subprocess.Popen(cmd.argv, stdin=stdin, stdout=stdout, stderr=stderr, env=env, cwd=proc_cwd)
6.281 + del stdin, stdout, stderr
6.282 + piped_commands.append(proc)
6.283 +
6.284 + try:
6.285 + next_node = pipeline.pop(0)
6.286 + except IndexError:
6.287 + try:
6.288 + retval = self._exec_piped_commands(piped_commands)
6.289 + if verbose:
6.290 + print "%s: exit code %i" % (' '.join(piped_commands_display), retval)
6.291 + finally:
6.292 + for f in files_to_close:
6.293 + if f is not dev_null:
6.294 + f.close()
6.295 + files_to_close = []
6.296 + return retval
6.297 + else:
6.298 +
6.299 + if isinstance(next_node, Pipe):
6.300 + state = PIPE
6.301 + piped_commands_display.append('|')
6.302 +
6.303 + elif isinstance(next_node, Or):
6.304 + try:
6.305 + this_retval = self._exec_piped_commands(piped_commands)
6.306 + finally:
6.307 + for f in files_to_close:
6.308 + if f is not dev_null:
6.309 + f.close()
6.310 + files_to_close = []
6.311 + if this_retval == 0:
6.312 + if verbose:
6.313 + print "%s: exit code %i (|| is short-circuited)" % (' '.join(piped_commands_display), retval)
6.314 + return this_retval
6.315 + if verbose:
6.316 + print "%s: exit code %i (|| proceeds)" % (' '.join(piped_commands_display), retval)
6.317 + state = BEGIN
6.318 + piped_commands = []
6.319 + piped_commands_display = []
6.320 +
6.321 + elif isinstance(next_node, And):
6.322 + try:
6.323 + this_retval = self._exec_piped_commands(piped_commands)
6.324 + finally:
6.325 + for f in files_to_close:
6.326 + if f is not dev_null:
6.327 + f.close()
6.328 + files_to_close = []
6.329 + if this_retval != 0:
6.330 + if verbose:
6.331 + print "%s: exit code %i (&& is short-circuited)" % (' '.join(piped_commands_display), retval)
6.332 + return this_retval
6.333 + if verbose:
6.334 + print "%s: exit code %i (&& proceeds)" % (' '.join(piped_commands_display), retval)
6.335 + state = BEGIN
6.336 + piped_commands = []
6.337 + piped_commands_display = []
6.338 +
6.339 +
6.340 +
6.341 +def _main():
6.342 + pipeline = Pipeline()
6.343 + pipeline.parse('./foo.py 2>&1 < xxx | cat && ls')
6.344 + print pipeline.run()
6.345 +
6.346 +if __name__ == '__main__':
6.347 + _main()
6.348 +
7.1 --- a/wscript Fri Oct 23 16:22:56 2009 +0400
7.2 +++ b/wscript Fri Oct 23 16:23:38 2009 +0400
7.3 @@ -27,6 +27,8 @@
7.4 import Configure
7.5 import Scripting
7.6
7.7 +sys.path.insert(0, os.path.abspath('waf-tools'))
7.8 +
7.9 import cflags # override the build profiles from waf
7.10 cflags.profiles = {
7.11 # profile name: [optimization_level, warnings_level, debug_level]