summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/data.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/data.py')
-rw-r--r--bitbake/lib/bb/data.py147
1 files changed, 76 insertions, 71 deletions
diff --git a/bitbake/lib/bb/data.py b/bitbake/lib/bb/data.py
index 97022853ca..505f42950f 100644
--- a/bitbake/lib/bb/data.py
+++ b/bitbake/lib/bb/data.py
@@ -4,14 +4,16 @@ BitBake 'Data' implementations
4Functions for interacting with the data structure used by the 4Functions for interacting with the data structure used by the
5BitBake build tools. 5BitBake build tools.
6 6
7The expandKeys and update_data are the most expensive 7expandKeys and datastore iteration are the most expensive
8operations. At night the cookie monster came by and 8operations. Updating overrides is now "on the fly" but still based
9on the idea of the cookie monster introduced by zecke:
10"At night the cookie monster came by and
9suggested 'give me cookies on setting the variables and 11suggested 'give me cookies on setting the variables and
10things will work out'. Taking this suggestion into account 12things will work out'. Taking this suggestion into account
11applying the skills from the not yet passed 'Entwurf und 13applying the skills from the not yet passed 'Entwurf und
12Analyse von Algorithmen' lecture and the cookie 14Analyse von Algorithmen' lecture and the cookie
13monster seems to be right. We will track setVar more carefully 15monster seems to be right. We will track setVar more carefully
14to have faster update_data and expandKeys operations. 16to have faster datastore operations."
15 17
16This is a trade-off between speed and memory again but 18This is a trade-off between speed and memory again but
17the speed is more critical here. 19the speed is more critical here.
@@ -26,11 +28,6 @@ the speed is more critical here.
26 28
27import sys, os, re 29import sys, os, re
28import hashlib 30import hashlib
29if sys.argv[0][-5:] == "pydoc":
30 path = os.path.dirname(os.path.dirname(sys.argv[1]))
31else:
32 path = os.path.dirname(os.path.dirname(sys.argv[0]))
33sys.path.insert(0, path)
34from itertools import groupby 31from itertools import groupby
35 32
36from bb import data_smart 33from bb import data_smart
@@ -70,10 +67,6 @@ def keys(d):
70 """Return a list of keys in d""" 67 """Return a list of keys in d"""
71 return d.keys() 68 return d.keys()
72 69
73
74__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
75__expand_python_regexp__ = re.compile(r"\${@.+?}")
76
77def expand(s, d, varname = None): 70def expand(s, d, varname = None):
78 """Variable expansion using the data store""" 71 """Variable expansion using the data store"""
79 return d.expand(s, varname) 72 return d.expand(s, varname)
@@ -121,8 +114,8 @@ def emit_var(var, o=sys.__stdout__, d = init(), all=False):
121 if d.getVarFlag(var, 'python', False) and func: 114 if d.getVarFlag(var, 'python', False) and func:
122 return False 115 return False
123 116
124 export = d.getVarFlag(var, "export", False) 117 export = bb.utils.to_boolean(d.getVarFlag(var, "export"))
125 unexport = d.getVarFlag(var, "unexport", False) 118 unexport = bb.utils.to_boolean(d.getVarFlag(var, "unexport"))
126 if not all and not export and not unexport and not func: 119 if not all and not export and not unexport and not func:
127 return False 120 return False
128 121
@@ -195,8 +188,8 @@ def emit_env(o=sys.__stdout__, d = init(), all=False):
195 188
196def exported_keys(d): 189def exported_keys(d):
197 return (key for key in d.keys() if not key.startswith('__') and 190 return (key for key in d.keys() if not key.startswith('__') and
198 d.getVarFlag(key, 'export', False) and 191 bb.utils.to_boolean(d.getVarFlag(key, 'export')) and
199 not d.getVarFlag(key, 'unexport', False)) 192 not bb.utils.to_boolean(d.getVarFlag(key, 'unexport')))
200 193
201def exported_vars(d): 194def exported_vars(d):
202 k = list(exported_keys(d)) 195 k = list(exported_keys(d))
@@ -226,7 +219,7 @@ def emit_func(func, o=sys.__stdout__, d = init()):
226 deps = newdeps 219 deps = newdeps
227 seen |= deps 220 seen |= deps
228 newdeps = set() 221 newdeps = set()
229 for dep in deps: 222 for dep in sorted(deps):
230 if d.getVarFlag(dep, "func", False) and not d.getVarFlag(dep, "python", False): 223 if d.getVarFlag(dep, "func", False) and not d.getVarFlag(dep, "python", False):
231 emit_var(dep, o, d, False) and o.write('\n') 224 emit_var(dep, o, d, False) and o.write('\n')
232 newdeps |= bb.codeparser.ShellParser(dep, logger).parse_shell(d.getVar(dep)) 225 newdeps |= bb.codeparser.ShellParser(dep, logger).parse_shell(d.getVar(dep))
@@ -268,65 +261,72 @@ def emit_func_python(func, o=sys.__stdout__, d = init()):
268 newdeps |= set((d.getVarFlag(dep, "vardeps") or "").split()) 261 newdeps |= set((d.getVarFlag(dep, "vardeps") or "").split())
269 newdeps -= seen 262 newdeps -= seen
270 263
271def update_data(d): 264def build_dependencies(key, keys, mod_funcs, shelldeps, varflagsexcl, ignored_vars, d, codeparsedata):
272 """Performs final steps upon the datastore, including application of overrides""" 265 def handle_contains(value, contains, exclusions, d):
273 d.finalize(parent = True) 266 newvalue = []
267 if value:
268 newvalue.append(str(value))
269 for k in sorted(contains):
270 if k in exclusions or k in ignored_vars:
271 continue
272 l = (d.getVar(k) or "").split()
273 for item in sorted(contains[k]):
274 for word in item.split():
275 if not word in l:
276 newvalue.append("\n%s{%s} = Unset" % (k, item))
277 break
278 else:
279 newvalue.append("\n%s{%s} = Set" % (k, item))
280 return "".join(newvalue)
281
282 def handle_remove(value, deps, removes, d):
283 for r in sorted(removes):
284 r2 = d.expandWithRefs(r, None)
285 value += "\n_remove of %s" % r
286 deps |= r2.references
287 deps = deps | (keys & r2.execs)
288 value = handle_contains(value, r2.contains, exclusions, d)
289 return value
274 290
275def build_dependencies(key, keys, shelldeps, varflagsexcl, d):
276 deps = set() 291 deps = set()
277 try: 292 try:
293 if key in mod_funcs:
294 exclusions = set()
295 moddep = bb.codeparser.modulecode_deps[key]
296 value = handle_contains("", moddep[3], exclusions, d)
297 return frozenset((moddep[0] | keys & moddep[1]) - ignored_vars), value
298
278 if key[-1] == ']': 299 if key[-1] == ']':
279 vf = key[:-1].split('[') 300 vf = key[:-1].split('[')
301 if vf[1] == "vardepvalueexclude":
302 return deps, ""
280 value, parser = d.getVarFlag(vf[0], vf[1], False, retparser=True) 303 value, parser = d.getVarFlag(vf[0], vf[1], False, retparser=True)
281 deps |= parser.references 304 deps |= parser.references
282 deps = deps | (keys & parser.execs) 305 deps = deps | (keys & parser.execs)
283 return deps, value 306 deps -= ignored_vars
307 return frozenset(deps), value
284 varflags = d.getVarFlags(key, ["vardeps", "vardepvalue", "vardepsexclude", "exports", "postfuncs", "prefuncs", "lineno", "filename"]) or {} 308 varflags = d.getVarFlags(key, ["vardeps", "vardepvalue", "vardepsexclude", "exports", "postfuncs", "prefuncs", "lineno", "filename"]) or {}
285 vardeps = varflags.get("vardeps") 309 vardeps = varflags.get("vardeps")
286 310 exclusions = varflags.get("vardepsexclude", "").split()
287 def handle_contains(value, contains, d):
288 newvalue = ""
289 for k in sorted(contains):
290 l = (d.getVar(k) or "").split()
291 for item in sorted(contains[k]):
292 for word in item.split():
293 if not word in l:
294 newvalue += "\n%s{%s} = Unset" % (k, item)
295 break
296 else:
297 newvalue += "\n%s{%s} = Set" % (k, item)
298 if not newvalue:
299 return value
300 if not value:
301 return newvalue
302 return value + newvalue
303
304 def handle_remove(value, deps, removes, d):
305 for r in sorted(removes):
306 r2 = d.expandWithRefs(r, None)
307 value += "\n_remove of %s" % r
308 deps |= r2.references
309 deps = deps | (keys & r2.execs)
310 return value
311 311
312 if "vardepvalue" in varflags: 312 if "vardepvalue" in varflags:
313 value = varflags.get("vardepvalue") 313 value = varflags.get("vardepvalue")
314 elif varflags.get("func"): 314 elif varflags.get("func"):
315 if varflags.get("python"): 315 if varflags.get("python"):
316 value = d.getVarFlag(key, "_content", False) 316 value = codeparsedata.getVarFlag(key, "_content", False)
317 parser = bb.codeparser.PythonParser(key, logger) 317 parser = bb.codeparser.PythonParser(key, logger)
318 parser.parse_python(value, filename=varflags.get("filename"), lineno=varflags.get("lineno")) 318 parser.parse_python(value, filename=varflags.get("filename"), lineno=varflags.get("lineno"))
319 deps = deps | parser.references 319 deps = deps | parser.references
320 deps = deps | (keys & parser.execs) 320 deps = deps | (keys & parser.execs)
321 value = handle_contains(value, parser.contains, d) 321 value = handle_contains(value, parser.contains, exclusions, d)
322 else: 322 else:
323 value, parsedvar = d.getVarFlag(key, "_content", False, retparser=True) 323 value, parsedvar = codeparsedata.getVarFlag(key, "_content", False, retparser=True)
324 parser = bb.codeparser.ShellParser(key, logger) 324 parser = bb.codeparser.ShellParser(key, logger)
325 parser.parse_shell(parsedvar.value) 325 parser.parse_shell(parsedvar.value)
326 deps = deps | shelldeps 326 deps = deps | shelldeps
327 deps = deps | parsedvar.references 327 deps = deps | parsedvar.references
328 deps = deps | (keys & parser.execs) | (keys & parsedvar.execs) 328 deps = deps | (keys & parser.execs) | (keys & parsedvar.execs)
329 value = handle_contains(value, parsedvar.contains, d) 329 value = handle_contains(value, parsedvar.contains, exclusions, d)
330 if hasattr(parsedvar, "removes"): 330 if hasattr(parsedvar, "removes"):
331 value = handle_remove(value, deps, parsedvar.removes, d) 331 value = handle_remove(value, deps, parsedvar.removes, d)
332 if vardeps is None: 332 if vardeps is None:
@@ -341,7 +341,7 @@ def build_dependencies(key, keys, shelldeps, varflagsexcl, d):
341 value, parser = d.getVarFlag(key, "_content", False, retparser=True) 341 value, parser = d.getVarFlag(key, "_content", False, retparser=True)
342 deps |= parser.references 342 deps |= parser.references
343 deps = deps | (keys & parser.execs) 343 deps = deps | (keys & parser.execs)
344 value = handle_contains(value, parser.contains, d) 344 value = handle_contains(value, parser.contains, exclusions, d)
345 if hasattr(parser, "removes"): 345 if hasattr(parser, "removes"):
346 value = handle_remove(value, deps, parser.removes, d) 346 value = handle_remove(value, deps, parser.removes, d)
347 347
@@ -361,43 +361,50 @@ def build_dependencies(key, keys, shelldeps, varflagsexcl, d):
361 deps |= set(varfdeps) 361 deps |= set(varfdeps)
362 362
363 deps |= set((vardeps or "").split()) 363 deps |= set((vardeps or "").split())
364 deps -= set(varflags.get("vardepsexclude", "").split()) 364 deps -= set(exclusions)
365 deps -= ignored_vars
365 except bb.parse.SkipRecipe: 366 except bb.parse.SkipRecipe:
366 raise 367 raise
367 except Exception as e: 368 except Exception as e:
368 bb.warn("Exception during build_dependencies for %s" % key) 369 bb.warn("Exception during build_dependencies for %s" % key)
369 raise 370 raise
370 return deps, value 371 return frozenset(deps), value
371 #bb.note("Variable %s references %s and calls %s" % (key, str(deps), str(execs))) 372 #bb.note("Variable %s references %s and calls %s" % (key, str(deps), str(execs)))
372 #d.setVarFlag(key, "vardeps", deps) 373 #d.setVarFlag(key, "vardeps", deps)
373 374
374def generate_dependencies(d, whitelist): 375def generate_dependencies(d, ignored_vars):
375 376
376 keys = set(key for key in d if not key.startswith("__")) 377 mod_funcs = set(bb.codeparser.modulecode_deps.keys())
377 shelldeps = set(key for key in d.getVar("__exportlist", False) if d.getVarFlag(key, "export", False) and not d.getVarFlag(key, "unexport", False)) 378 keys = set(key for key in d if not key.startswith("__")) | mod_funcs
379 shelldeps = set(key for key in d.getVar("__exportlist", False) if bb.utils.to_boolean(d.getVarFlag(key, "export")) and not bb.utils.to_boolean(d.getVarFlag(key, "unexport")))
378 varflagsexcl = d.getVar('BB_SIGNATURE_EXCLUDE_FLAGS') 380 varflagsexcl = d.getVar('BB_SIGNATURE_EXCLUDE_FLAGS')
379 381
382 codeparserd = d.createCopy()
383 for forced in (d.getVar('BB_HASH_CODEPARSER_VALS') or "").split():
384 key, value = forced.split("=", 1)
385 codeparserd.setVar(key, value)
386
380 deps = {} 387 deps = {}
381 values = {} 388 values = {}
382 389
383 tasklist = d.getVar('__BBTASKS', False) or [] 390 tasklist = d.getVar('__BBTASKS', False) or []
384 for task in tasklist: 391 for task in tasklist:
385 deps[task], values[task] = build_dependencies(task, keys, shelldeps, varflagsexcl, d) 392 deps[task], values[task] = build_dependencies(task, keys, mod_funcs, shelldeps, varflagsexcl, ignored_vars, d, codeparserd)
386 newdeps = deps[task] 393 newdeps = deps[task]
387 seen = set() 394 seen = set()
388 while newdeps: 395 while newdeps:
389 nextdeps = newdeps - whitelist 396 nextdeps = newdeps
390 seen |= nextdeps 397 seen |= nextdeps
391 newdeps = set() 398 newdeps = set()
392 for dep in nextdeps: 399 for dep in nextdeps:
393 if dep not in deps: 400 if dep not in deps:
394 deps[dep], values[dep] = build_dependencies(dep, keys, shelldeps, varflagsexcl, d) 401 deps[dep], values[dep] = build_dependencies(dep, keys, mod_funcs, shelldeps, varflagsexcl, ignored_vars, d, codeparserd)
395 newdeps |= deps[dep] 402 newdeps |= deps[dep]
396 newdeps -= seen 403 newdeps -= seen
397 #print "For %s: %s" % (task, str(deps[task])) 404 #print "For %s: %s" % (task, str(deps[task]))
398 return tasklist, deps, values 405 return tasklist, deps, values
399 406
400def generate_dependency_hash(tasklist, gendeps, lookupcache, whitelist, fn): 407def generate_dependency_hash(tasklist, gendeps, lookupcache, ignored_vars, fn):
401 taskdeps = {} 408 taskdeps = {}
402 basehash = {} 409 basehash = {}
403 410
@@ -406,9 +413,10 @@ def generate_dependency_hash(tasklist, gendeps, lookupcache, whitelist, fn):
406 413
407 if data is None: 414 if data is None:
408 bb.error("Task %s from %s seems to be empty?!" % (task, fn)) 415 bb.error("Task %s from %s seems to be empty?!" % (task, fn))
409 data = '' 416 data = []
417 else:
418 data = [data]
410 419
411 gendeps[task] -= whitelist
412 newdeps = gendeps[task] 420 newdeps = gendeps[task]
413 seen = set() 421 seen = set()
414 while newdeps: 422 while newdeps:
@@ -416,27 +424,24 @@ def generate_dependency_hash(tasklist, gendeps, lookupcache, whitelist, fn):
416 seen |= nextdeps 424 seen |= nextdeps
417 newdeps = set() 425 newdeps = set()
418 for dep in nextdeps: 426 for dep in nextdeps:
419 if dep in whitelist:
420 continue
421 gendeps[dep] -= whitelist
422 newdeps |= gendeps[dep] 427 newdeps |= gendeps[dep]
423 newdeps -= seen 428 newdeps -= seen
424 429
425 alldeps = sorted(seen) 430 alldeps = sorted(seen)
426 for dep in alldeps: 431 for dep in alldeps:
427 data = data + dep 432 data.append(dep)
428 var = lookupcache[dep] 433 var = lookupcache[dep]
429 if var is not None: 434 if var is not None:
430 data = data + str(var) 435 data.append(str(var))
431 k = fn + ":" + task 436 k = fn + ":" + task
432 basehash[k] = hashlib.sha256(data.encode("utf-8")).hexdigest() 437 basehash[k] = hashlib.sha256("".join(data).encode("utf-8")).hexdigest()
433 taskdeps[task] = alldeps 438 taskdeps[task] = frozenset(seen)
434 439
435 return taskdeps, basehash 440 return taskdeps, basehash
436 441
437def inherits_class(klass, d): 442def inherits_class(klass, d):
438 val = d.getVar('__inherit_cache', False) or [] 443 val = d.getVar('__inherit_cache', False) or []
439 needle = os.path.join('classes', '%s.bbclass' % klass) 444 needle = '/%s.bbclass' % klass
440 for v in val: 445 for v in val:
441 if v.endswith(needle): 446 if v.endswith(needle):
442 return True 447 return True