From 331dd9f96c58b0243aae87a51d8745c4e4cceb72 Mon Sep 17 00:00:00 2001 From: Thomas Nagy Date: Wed, 6 Jan 2016 17:53:55 +0100 Subject: [PATCH] Commands executed without a shell will merge flags of the form --- demos/c/wscript | 9 +++- waflib/Task.py | 104 +++++++++++++++++++++++++---------------- waflib/Tools/suncc.py | 5 +- waflib/Tools/suncxx.py | 4 +- 4 files changed, 75 insertions(+), 47 deletions(-) diff --git a/demos/c/wscript b/demos/c/wscript index b13103fa..25eb2270 100644 --- a/demos/c/wscript +++ b/demos/c/wscript @@ -66,7 +66,14 @@ def build(bld): bld.env.FOO =['m', 'ncurses'] bld.env.ST = '-L%s' - bld(rule='echo ${ST:FOO} ${ST:SRC}', always=True, source='wscript', shell=1) + bld.env.A = 'aye' + bld.env.B = 'doh' + bld.env.SRCA = ['aaa'] + bld(rule='echo ${ST:FOO} ${ST:SRC} ${A}${B} ${ST:SRCA} ${ST:SRC[0].abspath()}', + always=True, source='wscript', shell=1, name='Shell') + if not Utils.is_win32: + bld(rule='echo ${ST:FOO} ${ST:SRC} ${A}${B} ${ST:SRCA} ${ST:SRC[0].abspath()}', + always=True, source='wscript', shell=0, cls_keyword=lambda x:'Trying again', name='NoShell') # illustrate how to add a command 'foo' and to execute things in it if bld.cmd == 'foo': diff --git a/waflib/Task.py b/waflib/Task.py index dd2ef1c6..abdbd4c1 100644 --- a/waflib/Task.py +++ b/waflib/Task.py @@ -60,8 +60,13 @@ def f(tsk): if isinstance(xx, str): return [xx] return xx tsk.last_cmd = lst = [] + def merge(lst1, lst2): + if lst1 and lst2: + return lst1[:-1] + [lst1[-1] + lst2[0]] + lst2[1:] + return lst1 + lst2 %s - lst = [x for x in lst if x] + if '' in lst: + lst = [x for x in lst if x] return tsk.exec_command(lst, cwd=cwdx, env=env.env or None) ''' @@ -937,6 +942,7 @@ def funex(c): exec(c, dc) return dc['f'] +re_novar = re.compile(r"^(SRC|TGT)\W+.*?$") reg_act = re.compile(r"(?P\\)|(?P\$\$)|(?P\$\{(?P\w+)(?P.*?)\})", re.M) def compile_fun_shell(line): """ @@ -971,6 +977,10 @@ def compile_fun_shell(line): m = '[a.path_from(cwdx) for a in tsk.inputs]' elif m == 'TGT': m = '[a.path_from(cwdx) for a in tsk.outputs]' + elif re_novar.match(m): + m = '[tsk.inputs%s]' % m[3:] + elif re_novar.match(m): + m = '[tsk.outputs%s]' % m[3:] elif m[:3] not in ('tsk', 'gen', 'bld'): dvars.extend([var, meth[1:]]) m = '%r' % m @@ -988,56 +998,68 @@ def compile_fun_shell(line): Logs.debug('action: %s' % c.strip().splitlines()) return (funex(c), dvars) +reg_act_noshell = re.compile(r"(?P\s+)|(?P\$\{(?P\w+)(?P.*?)\})|(?P\S+)", re.M) def compile_fun_noshell(line): """ Create a compiled function to execute a process without the shell WARNING: this method may disappear anytime, so use compile_fun instead """ - extr = [] - def repl(match): - g = match.group - if g('dollar'): return "$" - elif g('backslash'): return '\\' - elif g('subst'): extr.append((g('var'), g('code'))); return "<<|@|>>" - return None - - line2 = reg_act.sub(repl, line) - params = line2.split('<<|@|>>') - assert(extr) - buf = [] dvars = [] + merge = False app = buf.append - for x, (var, meth) in enumerate(extr): - params[x] = params[x].strip() - if params[x]: - app("lst.extend(%r)" % params[x].split()) - if var == 'SRC': - if meth: app('lst.append(tsk.inputs%s)' % meth) - else: app("lst.extend([a.path_from(cwdx) for a in tsk.inputs])") - elif var == 'TGT': - if meth: app('lst.append(tsk.outputs%s)' % meth) - else: app("lst.extend([a.path_from(cwdx) for a in tsk.outputs])") - elif meth: - if meth.startswith(':'): - m = meth[1:] - if m == 'SRC': - m = '[a.path_from(cwdx) for a in tsk.inputs]' - elif m == 'TGT': - m = '[a.path_from(cwdx) for a in tsk.outputs]' - elif m[:3] not in ('tsk', 'gen', 'bld'): - dvars.extend([var, m]) - m = '%r' % m - app('lst.extend(tsk.colon(%r, %s))' % (var, m)) + for m in reg_act_noshell.finditer(line): + if m.group('space'): + merge = False + continue + elif m.group('text'): + app('[%r]' % m.group('text')) + elif m.group('subst'): + var = m.group('var') + code = m.group('code') + if var == 'SRC': + if code: + app('[tsk.inputs%s]' % code) + else: + app("[a.path_from(cwdx) for a in tsk.inputs]") + elif var == 'TGT': + if code: + app('[tsk.outputs%s]' % code) + else: + app("[a.path_from(cwdx) for a in tsk.outputs]") + elif code: + if code.startswith(':'): + # a composed variable ${FOO:OUT} + if not var in dvars: + dvars.append(var) + m = code[1:] + if m == 'SRC': + m = '[a.path_from(cwdx) for a in tsk.inputs]' + elif m == 'TGT': + m = '[a.path_from(cwdx) for a in tsk.outputs]' + elif re_novar.match(m): + m = '[tsk.inputs%s]' % m[3:] + elif re_novar.match(m): + m = '[tsk.outputs%s]' % m[3:] + elif m[:3] not in ('tsk', 'gen', 'bld'): + dvars.append(m) + m = '%r' % m + app('tsk.colon(%r, %s)' % (var, m)) + else: + # plain code such as ${tsk.inputs[0].abspath()} + app('gen.to_list(%s%s)' % (var, code)) else: - app('lst.extend(gen.to_list(%s%s))' % (var, meth)) - else: - app('lst.extend(to_list(env[%r]))' % var) - if not var in dvars: dvars.append(var) + # a plain variable such as # a plain variable like ${AR} + app('to_list(env[%r])' % var) + if not var in dvars: + dvars.append(var) + if merge: + tmp = 'merge(%s, %s)' % (buf[-2], buf[-1]) + del buf[-1] + buf[-1] = tmp + merge = True # next turn - if extr: - if params[-1]: - app("lst.extend(%r)" % params[-1].split()) + buf = ['lst.extend(%s)' % x for x in buf] fun = COMPILE_TEMPLATE_NOSHELL % "\n\t".join(buf) Logs.debug('action: %s' % fun.strip().splitlines()) return (funex(fun), dvars) diff --git a/waflib/Tools/suncc.py b/waflib/Tools/suncc.py index 4909854e..c2cbd449 100644 --- a/waflib/Tools/suncc.py +++ b/waflib/Tools/suncc.py @@ -21,7 +21,6 @@ def find_scc(conf): v.CC_NAME = 'sun' conf.get_suncc_version(cc) - @conf def scc_common_flags(conf): """ @@ -30,12 +29,12 @@ def scc_common_flags(conf): v = conf.env v['CC_SRC_F'] = [] - v['CC_TGT_F'] = ['-c', '-o'] + v['CC_TGT_F'] = ['-c', '-o', ''] # linker if not v['LINK_CC']: v['LINK_CC'] = v['CC'] v['CCLNK_SRC_F'] = '' - v['CCLNK_TGT_F'] = ['-o'] + v['CCLNK_TGT_F'] = ['-o', ''] v['CPPPATH_ST'] = '-I%s' v['DEFINES_ST'] = '-D%s' diff --git a/waflib/Tools/suncxx.py b/waflib/Tools/suncxx.py index 5a04b483..1448b565 100644 --- a/waflib/Tools/suncxx.py +++ b/waflib/Tools/suncxx.py @@ -28,12 +28,12 @@ def sxx_common_flags(conf): v = conf.env v['CXX_SRC_F'] = [] - v['CXX_TGT_F'] = ['-c', '-o'] + v['CXX_TGT_F'] = ['-c', '-o', ''] # linker if not v['LINK_CXX']: v['LINK_CXX'] = v['CXX'] v['CXXLNK_SRC_F'] = [] - v['CXXLNK_TGT_F'] = ['-o'] + v['CXXLNK_TGT_F'] = ['-o', ''] v['CPPPATH_ST'] = '-I%s' v['DEFINES_ST'] = '-D%s'