1*4882a593Smuzhiyun""" 2*4882a593SmuzhiyunBitBake 'Data' implementations 3*4882a593Smuzhiyun 4*4882a593SmuzhiyunFunctions for interacting with the data structure used by the 5*4882a593SmuzhiyunBitBake build tools. 6*4882a593Smuzhiyun 7*4882a593SmuzhiyunThe expandKeys and update_data are the most expensive 8*4882a593Smuzhiyunoperations. At night the cookie monster came by and 9*4882a593Smuzhiyunsuggested 'give me cookies on setting the variables and 10*4882a593Smuzhiyunthings will work out'. Taking this suggestion into account 11*4882a593Smuzhiyunapplying the skills from the not yet passed 'Entwurf und 12*4882a593SmuzhiyunAnalyse von Algorithmen' lecture and the cookie 13*4882a593Smuzhiyunmonster seems to be right. We will track setVar more carefully 14*4882a593Smuzhiyunto have faster update_data and expandKeys operations. 15*4882a593Smuzhiyun 16*4882a593SmuzhiyunThis is a trade-off between speed and memory again but 17*4882a593Smuzhiyunthe speed is more critical here. 18*4882a593Smuzhiyun""" 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun# Copyright (C) 2003, 2004 Chris Larson 21*4882a593Smuzhiyun# Copyright (C) 2005 Holger Hans Peter Freyther 22*4882a593Smuzhiyun# 23*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 24*4882a593Smuzhiyun# 25*4882a593Smuzhiyun# Based on functions from the base bb module, Copyright 2003 Holger Schurig 26*4882a593Smuzhiyun 27*4882a593Smuzhiyunimport sys, os, re 28*4882a593Smuzhiyunimport hashlib 29*4882a593Smuzhiyunif sys.argv[0][-5:] == "pydoc": 30*4882a593Smuzhiyun path = os.path.dirname(os.path.dirname(sys.argv[1])) 31*4882a593Smuzhiyunelse: 32*4882a593Smuzhiyun path = os.path.dirname(os.path.dirname(sys.argv[0])) 33*4882a593Smuzhiyunsys.path.insert(0, path) 34*4882a593Smuzhiyunfrom itertools import groupby 35*4882a593Smuzhiyun 36*4882a593Smuzhiyunfrom bb import data_smart 37*4882a593Smuzhiyunfrom bb import codeparser 38*4882a593Smuzhiyunimport bb 39*4882a593Smuzhiyun 40*4882a593Smuzhiyunlogger = data_smart.logger 41*4882a593Smuzhiyun_dict_type = data_smart.DataSmart 42*4882a593Smuzhiyun 43*4882a593Smuzhiyundef init(): 44*4882a593Smuzhiyun """Return a new object representing the Bitbake data""" 45*4882a593Smuzhiyun return _dict_type() 46*4882a593Smuzhiyun 47*4882a593Smuzhiyundef init_db(parent = None): 48*4882a593Smuzhiyun """Return a new object representing the Bitbake data, 49*4882a593Smuzhiyun optionally based on an existing object""" 50*4882a593Smuzhiyun if parent is not None: 51*4882a593Smuzhiyun return parent.createCopy() 52*4882a593Smuzhiyun else: 53*4882a593Smuzhiyun return _dict_type() 54*4882a593Smuzhiyun 55*4882a593Smuzhiyundef createCopy(source): 56*4882a593Smuzhiyun """Link the source set to the destination 57*4882a593Smuzhiyun If one does not find the value in the destination set, 58*4882a593Smuzhiyun search will go on to the source set to get the value. 59*4882a593Smuzhiyun Value from source are copy-on-write. i.e. any try to 60*4882a593Smuzhiyun modify one of them will end up putting the modified value 61*4882a593Smuzhiyun in the destination set. 62*4882a593Smuzhiyun """ 63*4882a593Smuzhiyun return source.createCopy() 64*4882a593Smuzhiyun 65*4882a593Smuzhiyundef initVar(var, d): 66*4882a593Smuzhiyun """Non-destructive var init for data structure""" 67*4882a593Smuzhiyun d.initVar(var) 68*4882a593Smuzhiyun 69*4882a593Smuzhiyundef keys(d): 70*4882a593Smuzhiyun """Return a list of keys in d""" 71*4882a593Smuzhiyun return d.keys() 72*4882a593Smuzhiyun 73*4882a593Smuzhiyun 74*4882a593Smuzhiyun__expand_var_regexp__ = re.compile(r"\${[^{}]+}") 75*4882a593Smuzhiyun__expand_python_regexp__ = re.compile(r"\${@.+?}") 76*4882a593Smuzhiyun 77*4882a593Smuzhiyundef expand(s, d, varname = None): 78*4882a593Smuzhiyun """Variable expansion using the data store""" 79*4882a593Smuzhiyun return d.expand(s, varname) 80*4882a593Smuzhiyun 81*4882a593Smuzhiyundef expandKeys(alterdata, readdata = None): 82*4882a593Smuzhiyun if readdata is None: 83*4882a593Smuzhiyun readdata = alterdata 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun todolist = {} 86*4882a593Smuzhiyun for key in alterdata: 87*4882a593Smuzhiyun if not '${' in key: 88*4882a593Smuzhiyun continue 89*4882a593Smuzhiyun 90*4882a593Smuzhiyun ekey = expand(key, readdata) 91*4882a593Smuzhiyun if key == ekey: 92*4882a593Smuzhiyun continue 93*4882a593Smuzhiyun todolist[key] = ekey 94*4882a593Smuzhiyun 95*4882a593Smuzhiyun # These two for loops are split for performance to maximise the 96*4882a593Smuzhiyun # usefulness of the expand cache 97*4882a593Smuzhiyun for key in sorted(todolist): 98*4882a593Smuzhiyun ekey = todolist[key] 99*4882a593Smuzhiyun newval = alterdata.getVar(ekey, False) 100*4882a593Smuzhiyun if newval is not None: 101*4882a593Smuzhiyun val = alterdata.getVar(key, False) 102*4882a593Smuzhiyun if val is not None: 103*4882a593Smuzhiyun bb.warn("Variable key %s (%s) replaces original key %s (%s)." % (key, val, ekey, newval)) 104*4882a593Smuzhiyun alterdata.renameVar(key, ekey) 105*4882a593Smuzhiyun 106*4882a593Smuzhiyundef inheritFromOS(d, savedenv, permitted): 107*4882a593Smuzhiyun """Inherit variables from the initial environment.""" 108*4882a593Smuzhiyun exportlist = bb.utils.preserved_envvars_exported() 109*4882a593Smuzhiyun for s in savedenv.keys(): 110*4882a593Smuzhiyun if s in permitted: 111*4882a593Smuzhiyun try: 112*4882a593Smuzhiyun d.setVar(s, savedenv.getVar(s), op = 'from env') 113*4882a593Smuzhiyun if s in exportlist: 114*4882a593Smuzhiyun d.setVarFlag(s, "export", True, op = 'auto env export') 115*4882a593Smuzhiyun except TypeError: 116*4882a593Smuzhiyun pass 117*4882a593Smuzhiyun 118*4882a593Smuzhiyundef emit_var(var, o=sys.__stdout__, d = init(), all=False): 119*4882a593Smuzhiyun """Emit a variable to be sourced by a shell.""" 120*4882a593Smuzhiyun func = d.getVarFlag(var, "func", False) 121*4882a593Smuzhiyun if d.getVarFlag(var, 'python', False) and func: 122*4882a593Smuzhiyun return False 123*4882a593Smuzhiyun 124*4882a593Smuzhiyun export = d.getVarFlag(var, "export", False) 125*4882a593Smuzhiyun unexport = d.getVarFlag(var, "unexport", False) 126*4882a593Smuzhiyun if not all and not export and not unexport and not func: 127*4882a593Smuzhiyun return False 128*4882a593Smuzhiyun 129*4882a593Smuzhiyun try: 130*4882a593Smuzhiyun if all: 131*4882a593Smuzhiyun oval = d.getVar(var, False) 132*4882a593Smuzhiyun val = d.getVar(var) 133*4882a593Smuzhiyun except (KeyboardInterrupt): 134*4882a593Smuzhiyun raise 135*4882a593Smuzhiyun except Exception as exc: 136*4882a593Smuzhiyun o.write('# expansion of %s threw %s: %s\n' % (var, exc.__class__.__name__, str(exc))) 137*4882a593Smuzhiyun return False 138*4882a593Smuzhiyun 139*4882a593Smuzhiyun if all: 140*4882a593Smuzhiyun d.varhistory.emit(var, oval, val, o, d) 141*4882a593Smuzhiyun 142*4882a593Smuzhiyun if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all: 143*4882a593Smuzhiyun return False 144*4882a593Smuzhiyun 145*4882a593Smuzhiyun varExpanded = d.expand(var) 146*4882a593Smuzhiyun 147*4882a593Smuzhiyun if unexport: 148*4882a593Smuzhiyun o.write('unset %s\n' % varExpanded) 149*4882a593Smuzhiyun return False 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun if val is None: 152*4882a593Smuzhiyun return False 153*4882a593Smuzhiyun 154*4882a593Smuzhiyun val = str(val) 155*4882a593Smuzhiyun 156*4882a593Smuzhiyun if varExpanded.startswith("BASH_FUNC_"): 157*4882a593Smuzhiyun varExpanded = varExpanded[10:-2] 158*4882a593Smuzhiyun val = val[3:] # Strip off "() " 159*4882a593Smuzhiyun o.write("%s() %s\n" % (varExpanded, val)) 160*4882a593Smuzhiyun o.write("export -f %s\n" % (varExpanded)) 161*4882a593Smuzhiyun return True 162*4882a593Smuzhiyun 163*4882a593Smuzhiyun if func: 164*4882a593Smuzhiyun # Write a comment indicating where the shell function came from (line number and filename) to make it easier 165*4882a593Smuzhiyun # for the user to diagnose task failures. This comment is also used by build.py to determine the metadata 166*4882a593Smuzhiyun # location of shell functions. 167*4882a593Smuzhiyun o.write("# line: {0}, file: {1}\n".format( 168*4882a593Smuzhiyun d.getVarFlag(var, "lineno", False), 169*4882a593Smuzhiyun d.getVarFlag(var, "filename", False))) 170*4882a593Smuzhiyun # NOTE: should probably check for unbalanced {} within the var 171*4882a593Smuzhiyun val = val.rstrip('\n') 172*4882a593Smuzhiyun o.write("%s() {\n%s\n}\n" % (varExpanded, val)) 173*4882a593Smuzhiyun return 1 174*4882a593Smuzhiyun 175*4882a593Smuzhiyun if export: 176*4882a593Smuzhiyun o.write('export ') 177*4882a593Smuzhiyun 178*4882a593Smuzhiyun # if we're going to output this within doublequotes, 179*4882a593Smuzhiyun # to a shell, we need to escape the quotes in the var 180*4882a593Smuzhiyun alter = re.sub('"', '\\"', val) 181*4882a593Smuzhiyun alter = re.sub('\n', ' \\\n', alter) 182*4882a593Smuzhiyun alter = re.sub('\\$', '\\\\$', alter) 183*4882a593Smuzhiyun o.write('%s="%s"\n' % (varExpanded, alter)) 184*4882a593Smuzhiyun return False 185*4882a593Smuzhiyun 186*4882a593Smuzhiyundef emit_env(o=sys.__stdout__, d = init(), all=False): 187*4882a593Smuzhiyun """Emits all items in the data store in a format such that it can be sourced by a shell.""" 188*4882a593Smuzhiyun 189*4882a593Smuzhiyun isfunc = lambda key: bool(d.getVarFlag(key, "func", False)) 190*4882a593Smuzhiyun keys = sorted((key for key in d.keys() if not key.startswith("__")), key=isfunc) 191*4882a593Smuzhiyun grouped = groupby(keys, isfunc) 192*4882a593Smuzhiyun for isfunc, keys in grouped: 193*4882a593Smuzhiyun for key in sorted(keys): 194*4882a593Smuzhiyun emit_var(key, o, d, all and not isfunc) and o.write('\n') 195*4882a593Smuzhiyun 196*4882a593Smuzhiyundef exported_keys(d): 197*4882a593Smuzhiyun return (key for key in d.keys() if not key.startswith('__') and 198*4882a593Smuzhiyun d.getVarFlag(key, 'export', False) and 199*4882a593Smuzhiyun not d.getVarFlag(key, 'unexport', False)) 200*4882a593Smuzhiyun 201*4882a593Smuzhiyundef exported_vars(d): 202*4882a593Smuzhiyun k = list(exported_keys(d)) 203*4882a593Smuzhiyun for key in k: 204*4882a593Smuzhiyun try: 205*4882a593Smuzhiyun value = d.getVar(key) 206*4882a593Smuzhiyun except Exception as err: 207*4882a593Smuzhiyun bb.warn("%s: Unable to export ${%s}: %s" % (d.getVar("FILE"), key, err)) 208*4882a593Smuzhiyun continue 209*4882a593Smuzhiyun 210*4882a593Smuzhiyun if value is not None: 211*4882a593Smuzhiyun yield key, str(value) 212*4882a593Smuzhiyun 213*4882a593Smuzhiyundef emit_func(func, o=sys.__stdout__, d = init()): 214*4882a593Smuzhiyun """Emits all items in the data store in a format such that it can be sourced by a shell.""" 215*4882a593Smuzhiyun 216*4882a593Smuzhiyun keys = (key for key in d.keys() if not key.startswith("__") and not d.getVarFlag(key, "func", False)) 217*4882a593Smuzhiyun for key in sorted(keys): 218*4882a593Smuzhiyun emit_var(key, o, d, False) 219*4882a593Smuzhiyun 220*4882a593Smuzhiyun o.write('\n') 221*4882a593Smuzhiyun emit_var(func, o, d, False) and o.write('\n') 222*4882a593Smuzhiyun newdeps = bb.codeparser.ShellParser(func, logger).parse_shell(d.getVar(func)) 223*4882a593Smuzhiyun newdeps |= set((d.getVarFlag(func, "vardeps") or "").split()) 224*4882a593Smuzhiyun seen = set() 225*4882a593Smuzhiyun while newdeps: 226*4882a593Smuzhiyun deps = newdeps 227*4882a593Smuzhiyun seen |= deps 228*4882a593Smuzhiyun newdeps = set() 229*4882a593Smuzhiyun for dep in sorted(deps): 230*4882a593Smuzhiyun if d.getVarFlag(dep, "func", False) and not d.getVarFlag(dep, "python", False): 231*4882a593Smuzhiyun emit_var(dep, o, d, False) and o.write('\n') 232*4882a593Smuzhiyun newdeps |= bb.codeparser.ShellParser(dep, logger).parse_shell(d.getVar(dep)) 233*4882a593Smuzhiyun newdeps |= set((d.getVarFlag(dep, "vardeps") or "").split()) 234*4882a593Smuzhiyun newdeps -= seen 235*4882a593Smuzhiyun 236*4882a593Smuzhiyun_functionfmt = """ 237*4882a593Smuzhiyundef {function}(d): 238*4882a593Smuzhiyun{body}""" 239*4882a593Smuzhiyun 240*4882a593Smuzhiyundef emit_func_python(func, o=sys.__stdout__, d = init()): 241*4882a593Smuzhiyun """Emits all items in the data store in a format such that it can be sourced by a shell.""" 242*4882a593Smuzhiyun 243*4882a593Smuzhiyun def write_func(func, o, call = False): 244*4882a593Smuzhiyun body = d.getVar(func, False) 245*4882a593Smuzhiyun if not body.startswith("def"): 246*4882a593Smuzhiyun body = _functionfmt.format(function=func, body=body) 247*4882a593Smuzhiyun 248*4882a593Smuzhiyun o.write(body.strip() + "\n\n") 249*4882a593Smuzhiyun if call: 250*4882a593Smuzhiyun o.write(func + "(d)" + "\n\n") 251*4882a593Smuzhiyun 252*4882a593Smuzhiyun write_func(func, o, True) 253*4882a593Smuzhiyun pp = bb.codeparser.PythonParser(func, logger) 254*4882a593Smuzhiyun pp.parse_python(d.getVar(func, False)) 255*4882a593Smuzhiyun newdeps = pp.execs 256*4882a593Smuzhiyun newdeps |= set((d.getVarFlag(func, "vardeps") or "").split()) 257*4882a593Smuzhiyun seen = set() 258*4882a593Smuzhiyun while newdeps: 259*4882a593Smuzhiyun deps = newdeps 260*4882a593Smuzhiyun seen |= deps 261*4882a593Smuzhiyun newdeps = set() 262*4882a593Smuzhiyun for dep in deps: 263*4882a593Smuzhiyun if d.getVarFlag(dep, "func", False) and d.getVarFlag(dep, "python", False): 264*4882a593Smuzhiyun write_func(dep, o) 265*4882a593Smuzhiyun pp = bb.codeparser.PythonParser(dep, logger) 266*4882a593Smuzhiyun pp.parse_python(d.getVar(dep, False)) 267*4882a593Smuzhiyun newdeps |= pp.execs 268*4882a593Smuzhiyun newdeps |= set((d.getVarFlag(dep, "vardeps") or "").split()) 269*4882a593Smuzhiyun newdeps -= seen 270*4882a593Smuzhiyun 271*4882a593Smuzhiyundef update_data(d): 272*4882a593Smuzhiyun """Performs final steps upon the datastore, including application of overrides""" 273*4882a593Smuzhiyun d.finalize(parent = True) 274*4882a593Smuzhiyun 275*4882a593Smuzhiyundef build_dependencies(key, keys, shelldeps, varflagsexcl, ignored_vars, d): 276*4882a593Smuzhiyun deps = set() 277*4882a593Smuzhiyun try: 278*4882a593Smuzhiyun if key[-1] == ']': 279*4882a593Smuzhiyun vf = key[:-1].split('[') 280*4882a593Smuzhiyun if vf[1] == "vardepvalueexclude": 281*4882a593Smuzhiyun return deps, "" 282*4882a593Smuzhiyun value, parser = d.getVarFlag(vf[0], vf[1], False, retparser=True) 283*4882a593Smuzhiyun deps |= parser.references 284*4882a593Smuzhiyun deps = deps | (keys & parser.execs) 285*4882a593Smuzhiyun return deps, value 286*4882a593Smuzhiyun varflags = d.getVarFlags(key, ["vardeps", "vardepvalue", "vardepsexclude", "exports", "postfuncs", "prefuncs", "lineno", "filename"]) or {} 287*4882a593Smuzhiyun vardeps = varflags.get("vardeps") 288*4882a593Smuzhiyun exclusions = varflags.get("vardepsexclude", "").split() 289*4882a593Smuzhiyun 290*4882a593Smuzhiyun def handle_contains(value, contains, exclusions, d): 291*4882a593Smuzhiyun newvalue = [] 292*4882a593Smuzhiyun if value: 293*4882a593Smuzhiyun newvalue.append(str(value)) 294*4882a593Smuzhiyun for k in sorted(contains): 295*4882a593Smuzhiyun if k in exclusions or k in ignored_vars: 296*4882a593Smuzhiyun continue 297*4882a593Smuzhiyun l = (d.getVar(k) or "").split() 298*4882a593Smuzhiyun for item in sorted(contains[k]): 299*4882a593Smuzhiyun for word in item.split(): 300*4882a593Smuzhiyun if not word in l: 301*4882a593Smuzhiyun newvalue.append("\n%s{%s} = Unset" % (k, item)) 302*4882a593Smuzhiyun break 303*4882a593Smuzhiyun else: 304*4882a593Smuzhiyun newvalue.append("\n%s{%s} = Set" % (k, item)) 305*4882a593Smuzhiyun return "".join(newvalue) 306*4882a593Smuzhiyun 307*4882a593Smuzhiyun def handle_remove(value, deps, removes, d): 308*4882a593Smuzhiyun for r in sorted(removes): 309*4882a593Smuzhiyun r2 = d.expandWithRefs(r, None) 310*4882a593Smuzhiyun value += "\n_remove of %s" % r 311*4882a593Smuzhiyun deps |= r2.references 312*4882a593Smuzhiyun deps = deps | (keys & r2.execs) 313*4882a593Smuzhiyun return value 314*4882a593Smuzhiyun 315*4882a593Smuzhiyun if "vardepvalue" in varflags: 316*4882a593Smuzhiyun value = varflags.get("vardepvalue") 317*4882a593Smuzhiyun elif varflags.get("func"): 318*4882a593Smuzhiyun if varflags.get("python"): 319*4882a593Smuzhiyun value = d.getVarFlag(key, "_content", False) 320*4882a593Smuzhiyun parser = bb.codeparser.PythonParser(key, logger) 321*4882a593Smuzhiyun parser.parse_python(value, filename=varflags.get("filename"), lineno=varflags.get("lineno")) 322*4882a593Smuzhiyun deps = deps | parser.references 323*4882a593Smuzhiyun deps = deps | (keys & parser.execs) 324*4882a593Smuzhiyun value = handle_contains(value, parser.contains, exclusions, d) 325*4882a593Smuzhiyun else: 326*4882a593Smuzhiyun value, parsedvar = d.getVarFlag(key, "_content", False, retparser=True) 327*4882a593Smuzhiyun parser = bb.codeparser.ShellParser(key, logger) 328*4882a593Smuzhiyun parser.parse_shell(parsedvar.value) 329*4882a593Smuzhiyun deps = deps | shelldeps 330*4882a593Smuzhiyun deps = deps | parsedvar.references 331*4882a593Smuzhiyun deps = deps | (keys & parser.execs) | (keys & parsedvar.execs) 332*4882a593Smuzhiyun value = handle_contains(value, parsedvar.contains, exclusions, d) 333*4882a593Smuzhiyun if hasattr(parsedvar, "removes"): 334*4882a593Smuzhiyun value = handle_remove(value, deps, parsedvar.removes, d) 335*4882a593Smuzhiyun if vardeps is None: 336*4882a593Smuzhiyun parser.log.flush() 337*4882a593Smuzhiyun if "prefuncs" in varflags: 338*4882a593Smuzhiyun deps = deps | set(varflags["prefuncs"].split()) 339*4882a593Smuzhiyun if "postfuncs" in varflags: 340*4882a593Smuzhiyun deps = deps | set(varflags["postfuncs"].split()) 341*4882a593Smuzhiyun if "exports" in varflags: 342*4882a593Smuzhiyun deps = deps | set(varflags["exports"].split()) 343*4882a593Smuzhiyun else: 344*4882a593Smuzhiyun value, parser = d.getVarFlag(key, "_content", False, retparser=True) 345*4882a593Smuzhiyun deps |= parser.references 346*4882a593Smuzhiyun deps = deps | (keys & parser.execs) 347*4882a593Smuzhiyun value = handle_contains(value, parser.contains, exclusions, d) 348*4882a593Smuzhiyun if hasattr(parser, "removes"): 349*4882a593Smuzhiyun value = handle_remove(value, deps, parser.removes, d) 350*4882a593Smuzhiyun 351*4882a593Smuzhiyun if "vardepvalueexclude" in varflags: 352*4882a593Smuzhiyun exclude = varflags.get("vardepvalueexclude") 353*4882a593Smuzhiyun for excl in exclude.split('|'): 354*4882a593Smuzhiyun if excl: 355*4882a593Smuzhiyun value = value.replace(excl, '') 356*4882a593Smuzhiyun 357*4882a593Smuzhiyun # Add varflags, assuming an exclusion list is set 358*4882a593Smuzhiyun if varflagsexcl: 359*4882a593Smuzhiyun varfdeps = [] 360*4882a593Smuzhiyun for f in varflags: 361*4882a593Smuzhiyun if f not in varflagsexcl: 362*4882a593Smuzhiyun varfdeps.append('%s[%s]' % (key, f)) 363*4882a593Smuzhiyun if varfdeps: 364*4882a593Smuzhiyun deps |= set(varfdeps) 365*4882a593Smuzhiyun 366*4882a593Smuzhiyun deps |= set((vardeps or "").split()) 367*4882a593Smuzhiyun deps -= set(exclusions) 368*4882a593Smuzhiyun except bb.parse.SkipRecipe: 369*4882a593Smuzhiyun raise 370*4882a593Smuzhiyun except Exception as e: 371*4882a593Smuzhiyun bb.warn("Exception during build_dependencies for %s" % key) 372*4882a593Smuzhiyun raise 373*4882a593Smuzhiyun return deps, value 374*4882a593Smuzhiyun #bb.note("Variable %s references %s and calls %s" % (key, str(deps), str(execs))) 375*4882a593Smuzhiyun #d.setVarFlag(key, "vardeps", deps) 376*4882a593Smuzhiyun 377*4882a593Smuzhiyundef generate_dependencies(d, ignored_vars): 378*4882a593Smuzhiyun 379*4882a593Smuzhiyun keys = set(key for key in d if not key.startswith("__")) 380*4882a593Smuzhiyun shelldeps = set(key for key in d.getVar("__exportlist", False) if d.getVarFlag(key, "export", False) and not d.getVarFlag(key, "unexport", False)) 381*4882a593Smuzhiyun varflagsexcl = d.getVar('BB_SIGNATURE_EXCLUDE_FLAGS') 382*4882a593Smuzhiyun 383*4882a593Smuzhiyun deps = {} 384*4882a593Smuzhiyun values = {} 385*4882a593Smuzhiyun 386*4882a593Smuzhiyun tasklist = d.getVar('__BBTASKS', False) or [] 387*4882a593Smuzhiyun for task in tasklist: 388*4882a593Smuzhiyun deps[task], values[task] = build_dependencies(task, keys, shelldeps, varflagsexcl, ignored_vars, d) 389*4882a593Smuzhiyun newdeps = deps[task] 390*4882a593Smuzhiyun seen = set() 391*4882a593Smuzhiyun while newdeps: 392*4882a593Smuzhiyun nextdeps = newdeps - ignored_vars 393*4882a593Smuzhiyun seen |= nextdeps 394*4882a593Smuzhiyun newdeps = set() 395*4882a593Smuzhiyun for dep in nextdeps: 396*4882a593Smuzhiyun if dep not in deps: 397*4882a593Smuzhiyun deps[dep], values[dep] = build_dependencies(dep, keys, shelldeps, varflagsexcl, ignored_vars, d) 398*4882a593Smuzhiyun newdeps |= deps[dep] 399*4882a593Smuzhiyun newdeps -= seen 400*4882a593Smuzhiyun #print "For %s: %s" % (task, str(deps[task])) 401*4882a593Smuzhiyun return tasklist, deps, values 402*4882a593Smuzhiyun 403*4882a593Smuzhiyundef generate_dependency_hash(tasklist, gendeps, lookupcache, ignored_vars, fn): 404*4882a593Smuzhiyun taskdeps = {} 405*4882a593Smuzhiyun basehash = {} 406*4882a593Smuzhiyun 407*4882a593Smuzhiyun for task in tasklist: 408*4882a593Smuzhiyun data = lookupcache[task] 409*4882a593Smuzhiyun 410*4882a593Smuzhiyun if data is None: 411*4882a593Smuzhiyun bb.error("Task %s from %s seems to be empty?!" % (task, fn)) 412*4882a593Smuzhiyun data = [] 413*4882a593Smuzhiyun else: 414*4882a593Smuzhiyun data = [data] 415*4882a593Smuzhiyun 416*4882a593Smuzhiyun gendeps[task] -= ignored_vars 417*4882a593Smuzhiyun newdeps = gendeps[task] 418*4882a593Smuzhiyun seen = set() 419*4882a593Smuzhiyun while newdeps: 420*4882a593Smuzhiyun nextdeps = newdeps 421*4882a593Smuzhiyun seen |= nextdeps 422*4882a593Smuzhiyun newdeps = set() 423*4882a593Smuzhiyun for dep in nextdeps: 424*4882a593Smuzhiyun if dep in ignored_vars: 425*4882a593Smuzhiyun continue 426*4882a593Smuzhiyun gendeps[dep] -= ignored_vars 427*4882a593Smuzhiyun newdeps |= gendeps[dep] 428*4882a593Smuzhiyun newdeps -= seen 429*4882a593Smuzhiyun 430*4882a593Smuzhiyun alldeps = sorted(seen) 431*4882a593Smuzhiyun for dep in alldeps: 432*4882a593Smuzhiyun data.append(dep) 433*4882a593Smuzhiyun var = lookupcache[dep] 434*4882a593Smuzhiyun if var is not None: 435*4882a593Smuzhiyun data.append(str(var)) 436*4882a593Smuzhiyun k = fn + ":" + task 437*4882a593Smuzhiyun basehash[k] = hashlib.sha256("".join(data).encode("utf-8")).hexdigest() 438*4882a593Smuzhiyun taskdeps[task] = alldeps 439*4882a593Smuzhiyun 440*4882a593Smuzhiyun return taskdeps, basehash 441*4882a593Smuzhiyun 442*4882a593Smuzhiyundef inherits_class(klass, d): 443*4882a593Smuzhiyun val = d.getVar('__inherit_cache', False) or [] 444*4882a593Smuzhiyun needle = os.path.join('classes', '%s.bbclass' % klass) 445*4882a593Smuzhiyun for v in val: 446*4882a593Smuzhiyun if v.endswith(needle): 447*4882a593Smuzhiyun return True 448*4882a593Smuzhiyun return False 449