summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2024-06-27 15:13:45 +0100
committerSteve Sakoman <steve@sakoman.com>2024-07-26 07:43:46 -0700
commit7b4cc330228d1853a74e85fb415f9a06b8183927 (patch)
tree9345f55fe47f72f7ec57fd34d0ba9e3c77d3d372 /bitbake
parent688146cd1893d81dc6deed56a05250c52e6432bb (diff)
downloadpoky-7b4cc330228d1853a74e85fb415f9a06b8183927.tar.gz
bitbake: codeparser/data: Ensure module function contents changing is accounted for
Currently, if a pylib function changes contents, the taskhash remains unchanged since we assume the functions have stable output. This is probably a poor assumption so take the code of the function into account in the taskhashes. This avoids certain frustrating build failures we've been seeing in automated testing. To make this work we have to add an extra entry to the python code parsing cache so that we can store the hashed function contents for efficiency as in the python module case, that isn't used as the key to the cache. The cache version changes since we're adding data to the cache. (Bitbake rev: 4bf332ccac283ca3440e81d8c781fcc23fe10b98) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org> (cherry picked from commit b2c3438ebe62793ebabe2c282534893908d520b4) Signed-off-by: Steve Sakoman <steve@sakoman.com>
Diffstat (limited to 'bitbake')
-rw-r--r--bitbake/lib/bb/codeparser.py28
-rw-r--r--bitbake/lib/bb/data.py2
2 files changed, 18 insertions, 12 deletions
diff --git a/bitbake/lib/bb/codeparser.py b/bitbake/lib/bb/codeparser.py
index 2e8b7ced3c..0b2890cf8a 100644
--- a/bitbake/lib/bb/codeparser.py
+++ b/bitbake/lib/bb/codeparser.py
@@ -82,14 +82,14 @@ def add_module_functions(fn, functions, namespace):
82 if e in functions: 82 if e in functions:
83 execs.remove(e) 83 execs.remove(e)
84 execs.add(namespace + "." + e) 84 execs.add(namespace + "." + e)
85 modulecode_deps[name] = [parser.references.copy(), execs, parser.var_execs.copy(), parser.contains.copy()] 85 modulecode_deps[name] = [parser.references.copy(), execs, parser.var_execs.copy(), parser.contains.copy(), parser.extra]
86 #bb.warn("%s: %s\nRefs:%s Execs: %s %s %s" % (name, fn, parser.references, parser.execs, parser.var_execs, parser.contains)) 86 #bb.warn("%s: %s\nRefs:%s Execs: %s %s %s" % (name, fn, parser.references, parser.execs, parser.var_execs, parser.contains))
87 87
88def update_module_dependencies(d): 88def update_module_dependencies(d):
89 for mod in modulecode_deps: 89 for mod in modulecode_deps:
90 excludes = set((d.getVarFlag(mod, "vardepsexclude") or "").split()) 90 excludes = set((d.getVarFlag(mod, "vardepsexclude") or "").split())
91 if excludes: 91 if excludes:
92 modulecode_deps[mod] = [modulecode_deps[mod][0] - excludes, modulecode_deps[mod][1] - excludes, modulecode_deps[mod][2] - excludes, modulecode_deps[mod][3]] 92 modulecode_deps[mod] = [modulecode_deps[mod][0] - excludes, modulecode_deps[mod][1] - excludes, modulecode_deps[mod][2] - excludes, modulecode_deps[mod][3], modulecode_deps[mod][4]]
93 93
94# A custom getstate/setstate using tuples is actually worth 15% cachesize by 94# A custom getstate/setstate using tuples is actually worth 15% cachesize by
95# avoiding duplication of the attribute names! 95# avoiding duplication of the attribute names!
@@ -112,21 +112,22 @@ class SetCache(object):
112codecache = SetCache() 112codecache = SetCache()
113 113
114class pythonCacheLine(object): 114class pythonCacheLine(object):
115 def __init__(self, refs, execs, contains): 115 def __init__(self, refs, execs, contains, extra):
116 self.refs = codecache.internSet(refs) 116 self.refs = codecache.internSet(refs)
117 self.execs = codecache.internSet(execs) 117 self.execs = codecache.internSet(execs)
118 self.contains = {} 118 self.contains = {}
119 for c in contains: 119 for c in contains:
120 self.contains[c] = codecache.internSet(contains[c]) 120 self.contains[c] = codecache.internSet(contains[c])
121 self.extra = extra
121 122
122 def __getstate__(self): 123 def __getstate__(self):
123 return (self.refs, self.execs, self.contains) 124 return (self.refs, self.execs, self.contains, self.extra)
124 125
125 def __setstate__(self, state): 126 def __setstate__(self, state):
126 (refs, execs, contains) = state 127 (refs, execs, contains, extra) = state
127 self.__init__(refs, execs, contains) 128 self.__init__(refs, execs, contains, extra)
128 def __hash__(self): 129 def __hash__(self):
129 l = (hash(self.refs), hash(self.execs)) 130 l = (hash(self.refs), hash(self.execs), hash(self.extra))
130 for c in sorted(self.contains.keys()): 131 for c in sorted(self.contains.keys()):
131 l = l + (c, hash(self.contains[c])) 132 l = l + (c, hash(self.contains[c]))
132 return hash(l) 133 return hash(l)
@@ -155,7 +156,7 @@ class CodeParserCache(MultiProcessCache):
155 # so that an existing cache gets invalidated. Additionally you'll need 156 # so that an existing cache gets invalidated. Additionally you'll need
156 # to increment __cache_version__ in cache.py in order to ensure that old 157 # to increment __cache_version__ in cache.py in order to ensure that old
157 # recipe caches don't trigger "Taskhash mismatch" errors. 158 # recipe caches don't trigger "Taskhash mismatch" errors.
158 CACHE_VERSION = 11 159 CACHE_VERSION = 12
159 160
160 def __init__(self): 161 def __init__(self):
161 MultiProcessCache.__init__(self) 162 MultiProcessCache.__init__(self)
@@ -169,8 +170,8 @@ class CodeParserCache(MultiProcessCache):
169 self.pythoncachelines = {} 170 self.pythoncachelines = {}
170 self.shellcachelines = {} 171 self.shellcachelines = {}
171 172
172 def newPythonCacheLine(self, refs, execs, contains): 173 def newPythonCacheLine(self, refs, execs, contains, extra):
173 cacheline = pythonCacheLine(refs, execs, contains) 174 cacheline = pythonCacheLine(refs, execs, contains, extra)
174 h = hash(cacheline) 175 h = hash(cacheline)
175 if h in self.pythoncachelines: 176 if h in self.pythoncachelines:
176 return self.pythoncachelines[h] 177 return self.pythoncachelines[h]
@@ -338,6 +339,7 @@ class PythonParser():
338 self.contains = {} 339 self.contains = {}
339 for i in codeparsercache.pythoncache[h].contains: 340 for i in codeparsercache.pythoncache[h].contains:
340 self.contains[i] = set(codeparsercache.pythoncache[h].contains[i]) 341 self.contains[i] = set(codeparsercache.pythoncache[h].contains[i])
342 self.extra = codeparsercache.pythoncache[h].extra
341 return 343 return
342 344
343 if h in codeparsercache.pythoncacheextras: 345 if h in codeparsercache.pythoncacheextras:
@@ -346,6 +348,7 @@ class PythonParser():
346 self.contains = {} 348 self.contains = {}
347 for i in codeparsercache.pythoncacheextras[h].contains: 349 for i in codeparsercache.pythoncacheextras[h].contains:
348 self.contains[i] = set(codeparsercache.pythoncacheextras[h].contains[i]) 350 self.contains[i] = set(codeparsercache.pythoncacheextras[h].contains[i])
351 self.extra = codeparsercache.pythoncacheextras[h].extra
349 return 352 return
350 353
351 if fixedhash and not node: 354 if fixedhash and not node:
@@ -364,8 +367,11 @@ class PythonParser():
364 self.visit_Call(n) 367 self.visit_Call(n)
365 368
366 self.execs.update(self.var_execs) 369 self.execs.update(self.var_execs)
370 self.extra = None
371 if fixedhash:
372 self.extra = bbhash(str(node))
367 373
368 codeparsercache.pythoncacheextras[h] = codeparsercache.newPythonCacheLine(self.references, self.execs, self.contains) 374 codeparsercache.pythoncacheextras[h] = codeparsercache.newPythonCacheLine(self.references, self.execs, self.contains, self.extra)
369 375
370class ShellParser(): 376class ShellParser():
371 def __init__(self, name, log): 377 def __init__(self, name, log):
diff --git a/bitbake/lib/bb/data.py b/bitbake/lib/bb/data.py
index 505f42950f..f672a84451 100644
--- a/bitbake/lib/bb/data.py
+++ b/bitbake/lib/bb/data.py
@@ -293,7 +293,7 @@ def build_dependencies(key, keys, mod_funcs, shelldeps, varflagsexcl, ignored_va
293 if key in mod_funcs: 293 if key in mod_funcs:
294 exclusions = set() 294 exclusions = set()
295 moddep = bb.codeparser.modulecode_deps[key] 295 moddep = bb.codeparser.modulecode_deps[key]
296 value = handle_contains("", moddep[3], exclusions, d) 296 value = handle_contains(moddep[4], moddep[3], exclusions, d)
297 return frozenset((moddep[0] | keys & moddep[1]) - ignored_vars), value 297 return frozenset((moddep[0] | keys & moddep[1]) - ignored_vars), value
298 298
299 if key[-1] == ']': 299 if key[-1] == ']':