diff options
Diffstat (limited to 'bitbake/lib/bb/data.py')
-rw-r--r-- | bitbake/lib/bb/data.py | 147 |
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 | |||
4 | Functions for interacting with the data structure used by the | 4 | Functions for interacting with the data structure used by the |
5 | BitBake build tools. | 5 | BitBake build tools. |
6 | 6 | ||
7 | The expandKeys and update_data are the most expensive | 7 | expandKeys and datastore iteration are the most expensive |
8 | operations. At night the cookie monster came by and | 8 | operations. Updating overrides is now "on the fly" but still based |
9 | on the idea of the cookie monster introduced by zecke: | ||
10 | "At night the cookie monster came by and | ||
9 | suggested 'give me cookies on setting the variables and | 11 | suggested 'give me cookies on setting the variables and |
10 | things will work out'. Taking this suggestion into account | 12 | things will work out'. Taking this suggestion into account |
11 | applying the skills from the not yet passed 'Entwurf und | 13 | applying the skills from the not yet passed 'Entwurf und |
12 | Analyse von Algorithmen' lecture and the cookie | 14 | Analyse von Algorithmen' lecture and the cookie |
13 | monster seems to be right. We will track setVar more carefully | 15 | monster seems to be right. We will track setVar more carefully |
14 | to have faster update_data and expandKeys operations. | 16 | to have faster datastore operations." |
15 | 17 | ||
16 | This is a trade-off between speed and memory again but | 18 | This is a trade-off between speed and memory again but |
17 | the speed is more critical here. | 19 | the speed is more critical here. |
@@ -26,11 +28,6 @@ the speed is more critical here. | |||
26 | 28 | ||
27 | import sys, os, re | 29 | import sys, os, re |
28 | import hashlib | 30 | import hashlib |
29 | if sys.argv[0][-5:] == "pydoc": | ||
30 | path = os.path.dirname(os.path.dirname(sys.argv[1])) | ||
31 | else: | ||
32 | path = os.path.dirname(os.path.dirname(sys.argv[0])) | ||
33 | sys.path.insert(0, path) | ||
34 | from itertools import groupby | 31 | from itertools import groupby |
35 | 32 | ||
36 | from bb import data_smart | 33 | from 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 | |||
77 | def expand(s, d, varname = None): | 70 | def 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 | ||
196 | def exported_keys(d): | 189 | def 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 | ||
201 | def exported_vars(d): | 194 | def 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 | ||
271 | def update_data(d): | 264 | def 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 | ||
275 | def 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 | ||
374 | def generate_dependencies(d, whitelist): | 375 | def 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 | ||
400 | def generate_dependency_hash(tasklist, gendeps, lookupcache, whitelist, fn): | 407 | def 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 | ||
437 | def inherits_class(klass, d): | 442 | def 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 |