summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2024-01-09 13:47:36 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2024-01-10 13:55:33 +0000
commitc665a2c93337fc372207af604c21bdea5babb4e5 (patch)
treeec5d60d5eb0a28eb3c9002cd81021dc5543a1f45
parent56b1af37dc61e06ef013b8c31248a91c475fffb1 (diff)
downloadpoky-c665a2c93337fc372207af604c21bdea5babb4e5.tar.gz
bitbake: ast: Fix EXPORT_FUNCTIONS bug
If you have two classes, both of which set EXPORT_FUNCTIONS for the same funciton and a standard funciton definition for the function that is exported, the export function can sometimes overwrite the standard one. The issue is that the internal flag the code uses isn't ovweritten if the variable is giving a new value. Fix the issue by using a comment in the code that is injected so that we know if it is ours or not. Also add some testing for EXPORT_FUNCTIONS, not perfect but a start. (Bitbake rev: 66306d5151acb0a26a171c338d8f60eb9eb16c6b) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/bb/parse/ast.py9
-rw-r--r--bitbake/lib/bb/tests/parse.py98
2 files changed, 103 insertions, 4 deletions
diff --git a/bitbake/lib/bb/parse/ast.py b/bitbake/lib/bb/parse/ast.py
index 6441c5cf7c..d30b688965 100644
--- a/bitbake/lib/bb/parse/ast.py
+++ b/bitbake/lib/bb/parse/ast.py
@@ -211,10 +211,12 @@ class ExportFuncsNode(AstNode):
211 211
212 def eval(self, data): 212 def eval(self, data):
213 213
214 sentinel = " # Export function set\n"
214 for func in self.n: 215 for func in self.n:
215 calledfunc = self.classname + "_" + func 216 calledfunc = self.classname + "_" + func
216 217
217 if data.getVar(func, False) and not data.getVarFlag(func, 'export_func', False): 218 basevar = data.getVar(func, False)
219 if basevar and sentinel not in basevar:
218 continue 220 continue
219 221
220 if data.getVar(func, False): 222 if data.getVar(func, False):
@@ -231,12 +233,11 @@ class ExportFuncsNode(AstNode):
231 data.setVarFlag(func, "lineno", 1) 233 data.setVarFlag(func, "lineno", 1)
232 234
233 if data.getVarFlag(calledfunc, "python", False): 235 if data.getVarFlag(calledfunc, "python", False):
234 data.setVar(func, " bb.build.exec_func('" + calledfunc + "', d)\n", parsing=True) 236 data.setVar(func, sentinel + " bb.build.exec_func('" + calledfunc + "', d)\n", parsing=True)
235 else: 237 else:
236 if "-" in self.classname: 238 if "-" in self.classname:
237 bb.fatal("The classname %s contains a dash character and is calling an sh function %s using EXPORT_FUNCTIONS. Since a dash is illegal in sh function names, this cannot work, please rename the class or don't use EXPORT_FUNCTIONS." % (self.classname, calledfunc)) 239 bb.fatal("The classname %s contains a dash character and is calling an sh function %s using EXPORT_FUNCTIONS. Since a dash is illegal in sh function names, this cannot work, please rename the class or don't use EXPORT_FUNCTIONS." % (self.classname, calledfunc))
238 data.setVar(func, " " + calledfunc + "\n", parsing=True) 240 data.setVar(func, sentinel + " " + calledfunc + "\n", parsing=True)
239 data.setVarFlag(func, 'export_func', '1')
240 241
241class AddTaskNode(AstNode): 242class AddTaskNode(AstNode):
242 def __init__(self, filename, lineno, func, before, after): 243 def __init__(self, filename, lineno, func, before, after):
diff --git a/bitbake/lib/bb/tests/parse.py b/bitbake/lib/bb/tests/parse.py
index 304bbbe222..72d1962e7e 100644
--- a/bitbake/lib/bb/tests/parse.py
+++ b/bitbake/lib/bb/tests/parse.py
@@ -243,3 +243,101 @@ unset A[flag@.service]
243 with self.assertRaises(bb.parse.ParseError): 243 with self.assertRaises(bb.parse.ParseError):
244 d = bb.parse.handle(f.name, self.d)[''] 244 d = bb.parse.handle(f.name, self.d)['']
245 245
246 export_function_recipe = """
247inherit someclass
248"""
249
250 export_function_recipe2 = """
251inherit someclass
252
253do_compile () {
254 false
255}
256
257python do_compilepython () {
258 bb.note("Something else")
259}
260
261"""
262 export_function_class = """
263someclass_do_compile() {
264 true
265}
266
267python someclass_do_compilepython () {
268 bb.note("Something")
269}
270
271EXPORT_FUNCTIONS do_compile do_compilepython
272"""
273
274 export_function_class2 = """
275secondclass_do_compile() {
276 true
277}
278
279python secondclass_do_compilepython () {
280 bb.note("Something")
281}
282
283EXPORT_FUNCTIONS do_compile do_compilepython
284"""
285
286 def test_parse_export_functions(self):
287 def check_function_flags(d):
288 self.assertEqual(d.getVarFlag("do_compile", "func"), 1)
289 self.assertEqual(d.getVarFlag("do_compilepython", "func"), 1)
290 self.assertEqual(d.getVarFlag("do_compile", "python"), None)
291 self.assertEqual(d.getVarFlag("do_compilepython", "python"), "1")
292
293 with tempfile.TemporaryDirectory() as tempdir:
294 self.d.setVar("__bbclasstype", "recipe")
295 recipename = tempdir + "/recipe.bb"
296 os.makedirs(tempdir + "/classes")
297 with open(tempdir + "/classes/someclass.bbclass", "w") as f:
298 f.write(self.export_function_class)
299 f.flush()
300 with open(tempdir + "/classes/secondclass.bbclass", "w") as f:
301 f.write(self.export_function_class2)
302 f.flush()
303
304 with open(recipename, "w") as f:
305 f.write(self.export_function_recipe)
306 f.flush()
307 os.chdir(tempdir)
308 d = bb.parse.handle(recipename, bb.data.createCopy(self.d))['']
309 self.assertIn("someclass_do_compile", d.getVar("do_compile"))
310 self.assertIn("someclass_do_compilepython", d.getVar("do_compilepython"))
311 check_function_flags(d)
312
313 recipename2 = tempdir + "/recipe2.bb"
314 with open(recipename2, "w") as f:
315 f.write(self.export_function_recipe2)
316 f.flush()
317
318 d = bb.parse.handle(recipename2, bb.data.createCopy(self.d))['']
319 self.assertNotIn("someclass_do_compile", d.getVar("do_compile"))
320 self.assertNotIn("someclass_do_compilepython", d.getVar("do_compilepython"))
321 self.assertIn("false", d.getVar("do_compile"))
322 self.assertIn("else", d.getVar("do_compilepython"))
323 check_function_flags(d)
324
325 with open(recipename, "a+") as f:
326 f.write("\ninherit secondclass\n")
327 f.flush()
328 with open(recipename2, "a+") as f:
329 f.write("\ninherit secondclass\n")
330 f.flush()
331
332 d = bb.parse.handle(recipename, bb.data.createCopy(self.d))['']
333 self.assertIn("secondclass_do_compile", d.getVar("do_compile"))
334 self.assertIn("secondclass_do_compilepython", d.getVar("do_compilepython"))
335 check_function_flags(d)
336
337 d = bb.parse.handle(recipename2, bb.data.createCopy(self.d))['']
338 self.assertNotIn("someclass_do_compile", d.getVar("do_compile"))
339 self.assertNotIn("someclass_do_compilepython", d.getVar("do_compilepython"))
340 self.assertIn("false", d.getVar("do_compile"))
341 self.assertIn("else", d.getVar("do_compilepython"))
342 check_function_flags(d)
343