#! /usr/bin/env python # encoding: utf-8 # WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file import os,re,sys,tempfile from waflib import Utils,Logs,Errors NOT_RUN=0 MISSING=1 CRASHED=2 EXCEPTION=3 SKIPPED=8 SUCCESS=9 ASK_LATER=-1 SKIP_ME=-2 RUN_ME=-3 COMPILE_TEMPLATE_SHELL=''' def f(tsk): env = tsk.env gen = tsk.generator bld = gen.bld cwdx = tsk.get_cwd() p = env.get_flat tsk.last_cmd = cmd = \'\'\' %s \'\'\' % s return tsk.exec_command(cmd, cwd=cwdx, env=env.env or None) ''' COMPILE_TEMPLATE_NOSHELL=''' def f(tsk): env = tsk.env gen = tsk.generator bld = gen.bld cwdx = tsk.get_cwd() def to_list(xx): if isinstance(xx, str): return [xx] return xx def merge(lst1, lst2): if lst1 and lst2: return lst1[:-1] + [lst1[-1] + lst2[0]] + lst2[1:] return lst1 + lst2 lst = [] %s if '' in lst: lst = [x for x in lst if x] tsk.last_cmd = lst return tsk.exec_command(lst, cwd=cwdx, env=env.env or None) ''' classes={} class store_task_type(type): def __init__(cls,name,bases,dict): super(store_task_type,cls).__init__(name,bases,dict) name=cls.__name__ if name!='evil'and name!='TaskBase': global classes if getattr(cls,'run_str',None): (f,dvars)=compile_fun(cls.run_str,cls.shell) cls.hcode=Utils.h_cmd(cls.run_str) cls.orig_run_str=cls.run_str cls.run_str=None cls.run=f cls.vars=list(set(cls.vars+dvars)) cls.vars.sort() elif getattr(cls,'run',None)and not'hcode'in cls.__dict__: cls.hcode=Utils.h_cmd(cls.run) getattr(cls,'register',classes)[name]=cls evil=store_task_type('evil',(object,),{}) class TaskBase(evil): color='GREEN' ext_in=[] ext_out=[] before=[] after=[] hcode='' __slots__=('hasrun','generator') def __init__(self,*k,**kw): self.hasrun=NOT_RUN try: self.generator=kw['generator'] except KeyError: self.generator=self def __repr__(self): return'\n\t{task %r: %s %s}'%(self.__class__.__name__,id(self),str(getattr(self,'fun',''))) def __str__(self): if hasattr(self,'fun'): return self.fun.__name__ return self.__class__.__name__ def keyword(self): if hasattr(self,'fun'): return'Function' return'Processing' def get_cwd(self): bld=self.generator.bld ret=getattr(self,'cwd',None)or getattr(self.generator.bld,'cwd',bld.bldnode) if isinstance(ret,str): self.generator.bld.fatal('Working folders given to tasks must be Node objects') return ret def quote_flag(self,x): old=x if'\\'in x: x=x.replace('\\','\\\\') if'"'in x: x=x.replace('"','\\"') if old!=x or' 'in x or'\t'in x or"'"in x: x='"%s"'%x return x def split_argfile(self,cmd): return([cmd[0]],[self.quote_flag(x)for x in cmd[1:]]) def exec_command(self,cmd,**kw): if not'cwd'in kw: kw['cwd']=self.get_cwd() if self.env.PATH: env=kw['env']=dict(kw.get('env')or self.env.env or os.environ) env['PATH']=self.env.PATH if isinstance(self.env.PATH,str)else os.pathsep.join(self.env.PATH) if not isinstance(cmd,str)and(len(repr(cmd))>=8192 if Utils.is_win32 else len(cmd)>200000): cmd,args=self.split_argfile(cmd) try: (fd,tmp)=tempfile.mkstemp() os.write(fd,'\r\n'.join(args)) os.close(fd) return self.generator.bld.exec_command(cmd+['@'+tmp],**kw) finally: try: os.remove(tmp) except OSError: pass else: return self.generator.bld.exec_command(cmd,**kw) def runnable_status(self): return RUN_ME def uid(self): return Utils.SIG_NIL def process(self): m=self.generator.bld.producer try: del self.generator.bld.task_sigs[self.uid()] except KeyError: pass try: ret=self.run() except Exception: self.err_msg=Utils.ex_stack() self.hasrun=EXCEPTION m.error_handler(self) return if ret: self.err_code=ret self.hasrun=CRASHED else: try: self.post_run() except Errors.WafError: pass except Exception: self.err_msg=Utils.ex_stack() self.hasrun=EXCEPTION else: self.hasrun=SUCCESS if self.hasrun!=SUCCESS: m.error_handler(self) def run(self): if hasattr(self,'fun'): return self.fun(self) return 0 def post_run(self): pass def log_display(self,bld): if self.generator.bld.progress_bar==3: return s=self.display() if s: if bld.logger: logger=bld.logger else: logger=Logs if self.generator.bld.progress_bar==1: c1=Logs.colors.cursor_off c2=Logs.colors.cursor_on logger.info(s,extra={'stream':sys.stderr,'terminator':'','c1':c1,'c2':c2}) else: logger.info(s,extra={'terminator':'','c1':'','c2':''}) def display(self): col1=Logs.colors(self.color) col2=Logs.colors.NORMAL master=self.generator.bld.producer def cur(): tmp=-1 if hasattr(master,'ready'): tmp-=master.ready.qsize() return master.processed+tmp if self.generator.bld.progress_bar==1: return self.generator.bld.progress_line(cur(),master.total,col1,col2) if self.generator.bld.progress_bar==2: ela=str(self.generator.bld.timer) try: ins=','.join([n.name for n in self.inputs]) except AttributeError: ins='' try: outs=','.join([n.name for n in self.outputs]) except AttributeError: outs='' return'|Total %s|Current %s|Inputs %s|Outputs %s|Time %s|\n'%(master.total,cur(),ins,outs,ela) s=str(self) if not s: return None total=master.total n=len(str(total)) fs='[%%%dd/%%%dd] %%s%%s%%s%%s\n'%(n,n) kw=self.keyword() if kw: kw+=' ' return fs%(cur(),total,kw,col1,s,col2) def hash_constraints(self): cls=self.__class__ tup=(str(cls.before),str(cls.after),str(cls.ext_in),str(cls.ext_out),cls.__name__,cls.hcode) return hash(tup) def format_error(self): msg=getattr(self,'last_cmd','') name=getattr(self.generator,'name','') if getattr(self,"err_msg",None): return self.err_msg elif not self.hasrun: return'task in %r was not executed for some reason: %r'%(name,self) elif self.hasrun==CRASHED: try: return' -> task in %r failed (exit status %r): %r\n%r'%(name,self.err_code,self,msg) except AttributeError: return' -> task in %r failed: %r\n%r'%(name,self,msg) elif self.hasrun==MISSING: return' -> missing files in %r: %r\n%r'%(name,self,msg) else: return'invalid status for task in %r: %r'%(name,self.hasrun) def colon(self,var1,var2): tmp=self.env[var1] if not tmp: return[] if isinstance(var2,str): it=self.env[var2] else: it=var2 if isinstance(tmp,str): return[tmp%x for x in it] else: lst=[] for y in it: lst.extend(tmp) lst.append(y) return lst class Task(TaskBase): vars=[] always_run=False shell=False def __init__(self,*k,**kw): TaskBase.__init__(self,*k,**kw) self.env=kw['env'] self.inputs=[] self.outputs=[] self.dep_nodes=[] self.run_after=set([]) def __str__(self): name=self.__class__.__name__ if self.outputs: if name.endswith(('lib','program'))or not self.inputs: node=self.outputs[0] return node.path_from(node.ctx.launch_node()) if not(self.inputs or self.outputs): return self.__class__.__name__ if len(self.inputs)==1: node=self.inputs[0] return node.path_from(node.ctx.launch_node()) src_str=' '.join([a.path_from(a.ctx.launch_node())for a in self.inputs]) tgt_str=' '.join([a.path_from(a.ctx.launch_node())for a in self.outputs]) if self.outputs:sep=' -> ' else:sep='' return'%s: %s%s%s'%(self.__class__.__name__,src_str,sep,tgt_str) def keyword(self): name=self.__class__.__name__ if name.endswith(('lib','program')): return'Linking' if len(self.inputs)==1 and len(self.outputs)==1: return'Compiling' if not self.inputs: if self.outputs: return'Creating' else: return'Running' return'Processing' def __repr__(self): try: ins=",".join([x.name for x in self.inputs]) outs=",".join([x.name for x in self.outputs]) except AttributeError: ins=",".join([str(x)for x in self.inputs]) outs=",".join([str(x)for x in self.outputs]) return"".join(['\n\t{task %r: '%id(self),self.__class__.__name__," ",ins," -> ",outs,'}']) def uid(self): try: return self.uid_ except AttributeError: m=Utils.md5(self.__class__.__name__) up=m.update for x in self.inputs+self.outputs: up(x.abspath()) self.uid_=m.digest() return self.uid_ def set_inputs(self,inp): if isinstance(inp,list):self.inputs+=inp else:self.inputs.append(inp) def set_outputs(self,out): if isinstance(out,list):self.outputs+=out else:self.outputs.append(out) def set_run_after(self,task): assert isinstance(task,TaskBase) self.run_after.add(task) def signature(self): try: return self.cache_sig except AttributeError: pass self.m=Utils.md5(self.hcode) self.sig_explicit_deps() self.sig_vars() if self.scan: try: self.sig_implicit_deps() except Errors.TaskRescan: return self.signature() ret=self.cache_sig=self.m.digest() return ret def runnable_status(self): for t in self.run_after: if not t.hasrun: return ASK_LATER try: new_sig=self.signature() except Errors.TaskNotReady: return ASK_LATER bld=self.generator.bld key=self.uid() try: prev_sig=bld.task_sigs[key] except KeyError: Logs.debug('task: task %r must run: it was never run before or the task code changed',self) return RUN_ME if new_sig!=prev_sig: Logs.debug('task: task %r must run: the task signature changed',self) return RUN_ME for node in self.outputs: sig=bld.node_sigs.get(node) if not sig: Logs.debug('task: task %r must run: an output node has no signature',self) return RUN_ME if sig!=key: Logs.debug('task: task %r must run: an output node was produced by another task',self) return RUN_ME if not node.exists(): Logs.debug('task: task %r must run: an output node does not exist',self) return RUN_ME return(self.always_run and RUN_ME)or SKIP_ME def post_run(self): bld=self.generator.bld for node in self.outputs: if not node.exists(): self.hasrun=MISSING self.err_msg='-> missing file: %r'%node.abspath() raise Errors.WafError(self.err_msg) bld.node_sigs[node]=self.uid() bld.task_sigs[self.uid()]=self.signature() try: del self.last_cmd except AttributeError: pass def sig_explicit_deps(self): bld=self.generator.bld upd=self.m.update for x in self.inputs+self.dep_nodes: upd(x.get_bld_sig()) if bld.deps_man: additional_deps=bld.deps_man for x in self.inputs+self.outputs: try: d=additional_deps[x] except KeyError: continue for v in d: if isinstance(v,bld.root.__class__): v=v.get_bld_sig() elif hasattr(v,'__call__'): v=v() upd(v) def sig_vars(self): sig=self.generator.bld.hash_env_vars(self.env,self.__class__.vars) self.m.update(sig) scan=None def sig_implicit_deps(self): bld=self.generator.bld key=self.uid() prev=bld.imp_sigs.get(key,[]) if prev: try: if prev==self.compute_sig_implicit_deps(): return prev except Errors.TaskNotReady: raise except EnvironmentError: for x in bld.node_deps.get(self.uid(),[]): if not x.is_bld()and not x.exists(): try: del x.parent.children[x.name] except KeyError: pass del bld.imp_sigs[key] raise Errors.TaskRescan('rescan') (bld.node_deps[key],bld.raw_deps[key])=self.scan() if Logs.verbose: Logs.debug('deps: scanner for %s: %r; unresolved: %r',self,bld.node_deps[key],bld.raw_deps[key]) try: bld.imp_sigs[key]=self.compute_sig_implicit_deps() except EnvironmentError: for k in bld.node_deps.get(self.uid(),[]): if not k.exists(): Logs.warn('Dependency %r for %r is missing: check the task declaration and the build order!',k,self) raise def compute_sig_implicit_deps(self): upd=self.m.update self.are_implicit_nodes_ready() for k in self.generator.bld.node_deps.get(self.uid(),[]): upd(k.get_bld_sig()) return self.m.digest() def are_implicit_nodes_ready(self): bld=self.generator.bld try: cache=bld.dct_implicit_nodes except AttributeError: bld.dct_implicit_nodes=cache={} try: dct=cache[bld.cur] except KeyError: dct=cache[bld.cur]={} for tsk in bld.cur_tasks: for x in tsk.outputs: dct[x]=tsk modified=False for x in bld.node_deps.get(self.uid(),[]): if x in dct: self.run_after.add(dct[x]) modified=True if modified: for tsk in self.run_after: if not tsk.hasrun: raise Errors.TaskNotReady('not ready') if sys.hexversion>0x3000000: def uid(self): try: return self.uid_ except AttributeError: m=Utils.md5(self.__class__.__name__.encode('iso8859-1','xmlcharrefreplace')) up=m.update for x in self.inputs+self.outputs: up(x.abspath().encode('iso8859-1','xmlcharrefreplace')) self.uid_=m.digest() return self.uid_ uid.__doc__=Task.uid.__doc__ Task.uid=uid def is_before(t1,t2): to_list=Utils.to_list for k in to_list(t2.ext_in): if k in to_list(t1.ext_out): return 1 if t1.__class__.__name__ in to_list(t2.after): return 1 if t2.__class__.__name__ in to_list(t1.before): return 1 return 0 def set_file_constraints(tasks): ins=Utils.defaultdict(set) outs=Utils.defaultdict(set) for x in tasks: for a in getattr(x,'inputs',[])+getattr(x,'dep_nodes',[]): ins[id(a)].add(x) for a in getattr(x,'outputs',[]): outs[id(a)].add(x) links=set(ins.keys()).intersection(outs.keys()) for k in links: for a in ins[k]: a.run_after.update(outs[k]) def set_precedence_constraints(tasks): cstr_groups=Utils.defaultdict(list) for x in tasks: h=x.hash_constraints() cstr_groups[h].append(x) keys=list(cstr_groups.keys()) maxi=len(keys) for i in range(maxi): t1=cstr_groups[keys[i]][0] for j in range(i+1,maxi): t2=cstr_groups[keys[j]][0] if is_before(t1,t2): a=i b=j elif is_before(t2,t1): a=j b=i else: continue aval=set(cstr_groups[keys[a]]) for x in cstr_groups[keys[b]]: x.run_after.update(aval) def funex(c): dc={} exec(c,dc) return dc['f'] re_cond=re.compile('(?P\w+)|(?P\|)|(?P&)') 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): 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"%s" return None line=reg_act.sub(repl,line)or line def replc(m): if m.group('and'): return' and ' elif m.group('or'): return' or ' else: x=m.group('var') if x not in dvars: dvars.append(x) return'env[%r]'%x parm=[] dvars=[] app=parm.append for(var,meth)in extr: if var=='SRC': if meth:app('tsk.inputs%s'%meth) else:app('" ".join([a.path_from(cwdx) for a in tsk.inputs])') elif var=='TGT': if meth:app('tsk.outputs%s'%meth) else:app('" ".join([a.path_from(cwdx) for a in tsk.outputs])') elif meth: if meth.startswith(':'): if var not in dvars: dvars.append(var) 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 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(meth[1:]) m='%r'%m app('" ".join(tsk.colon(%r, %s))'%(var,m)) elif meth.startswith('?'): expr=re_cond.sub(replc,meth[1:]) app('p(%r) if (%s) else ""'%(var,expr)) else: app('%s%s'%(var,meth)) else: if var not in dvars: dvars.append(var) app("p('%s')"%var) if parm:parm="%% (%s) "%(',\n\t\t'.join(parm)) else:parm='' c=COMPILE_TEMPLATE_SHELL%(line,parm) 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): buf=[] dvars=[] merge=False app=buf.append def replc(m): if m.group('and'): return' and ' elif m.group('or'): return' or ' else: x=m.group('var') if x not in dvars: dvars.append(x) return'env[%r]'%x 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(':'): 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)) elif code.startswith('?'): expr=re_cond.sub(replc,code[1:]) app('to_list(env[%r] if (%s) else [])'%(var,expr)) else: app('gen.to_list(%s%s)'%(var,code)) else: 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 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) def compile_fun(line,shell=False): if isinstance(line,str): if line.find('<')>0 or line.find('>')>0 or line.find('&&')>0: shell=True else: dvars_lst=[] funs_lst=[] for x in line: if isinstance(x,str): fun,dvars=compile_fun(x,shell) dvars_lst+=dvars funs_lst.append(fun) else: funs_lst.append(x) def composed_fun(task): for x in funs_lst: ret=x(task) if ret: return ret return None return composed_fun,dvars if shell: return compile_fun_shell(line) else: return compile_fun_noshell(line) def task_factory(name,func=None,vars=None,color='GREEN',ext_in=[],ext_out=[],before=[],after=[],shell=False,scan=None): params={'vars':vars or[],'color':color,'name':name,'ext_in':Utils.to_list(ext_in),'ext_out':Utils.to_list(ext_out),'before':Utils.to_list(before),'after':Utils.to_list(after),'shell':shell,'scan':scan,} if isinstance(func,str)or isinstance(func,tuple): params['run_str']=func else: params['run']=func cls=type(Task)(name,(Task,),params) global classes classes[name]=cls return cls def always_run(cls): Logs.warn('This decorator is deprecated, set always_run on the task class instead!') cls.always_run=True return cls def update_outputs(cls): return cls