summaryrefslogtreecommitdiffstats
path: root/meta/classes/staging.bbclass
diff options
context:
space:
mode:
Diffstat (limited to 'meta/classes/staging.bbclass')
-rw-r--r--meta/classes/staging.bbclass349
1 files changed, 347 insertions, 2 deletions
diff --git a/meta/classes/staging.bbclass b/meta/classes/staging.bbclass
index 2512ae6f5d..1a4668e5d3 100644
--- a/meta/classes/staging.bbclass
+++ b/meta/classes/staging.bbclass
@@ -235,12 +235,357 @@ do_populate_sysroot[depends] += "${POPULATESYSROOTDEPS}"
235SSTATETASKS += "do_populate_sysroot" 235SSTATETASKS += "do_populate_sysroot"
236do_populate_sysroot[cleandirs] = "${SYSROOT_DESTDIR}" 236do_populate_sysroot[cleandirs] = "${SYSROOT_DESTDIR}"
237do_populate_sysroot[sstate-inputdirs] = "${SYSROOT_DESTDIR}" 237do_populate_sysroot[sstate-inputdirs] = "${SYSROOT_DESTDIR}"
238do_populate_sysroot[sstate-outputdirs] = "${STAGING_DIR_HOST}/" 238do_populate_sysroot[sstate-outputdirs] = "${STAGING_DIR}-components/${PACKAGE_ARCH}/${PN}"
239do_populate_sysroot[stamp-extra-info] = "${MACHINE}" 239do_populate_sysroot[sstate-fixmedir] = "${STAGING_DIR}-components/${PACKAGE_ARCH}/${PN}"
240 240
241python do_populate_sysroot_setscene () { 241python do_populate_sysroot_setscene () {
242 sstate_setscene(d) 242 sstate_setscene(d)
243} 243}
244addtask do_populate_sysroot_setscene 244addtask do_populate_sysroot_setscene
245 245
246def staging_copyfile(c, target, fixme, postinsts, stagingdir):
247 import errno
248
249 if c.endswith("/fixmepath"):
250 fixme.append(c)
251 return None
252 if c.endswith("/fixmepath.cmd"):
253 return None
254 #bb.warn(c)
255 dest = c.replace(stagingdir, "")
256 dest = target + "/" + "/".join(dest.split("/")[3:])
257 bb.utils.mkdirhier(os.path.dirname(dest))
258 if "/usr/bin/postinst-" in c:
259 postinsts.append(dest)
260 if os.path.islink(c):
261 linkto = os.readlink(c)
262 if os.path.lexists(dest):
263 if os.readlink(dest) == linkto:
264 return dest
265 bb.fatal("Link %s already exists to a different location?" % dest)
266 os.symlink(linkto, dest)
267 #bb.warn(c)
268 else:
269 try:
270 os.link(c, dest)
271 except OSError as err:
272 if err.errno == errno.EXDEV:
273 bb.utils.copyfile(c, dest)
274 else:
275 raise
276 return dest
277
278def staging_copydir(c, target, stagingdir):
279 dest = c.replace(stagingdir, "")
280 dest = target + "/" + "/".join(dest.split("/")[3:])
281 bb.utils.mkdirhier(dest)
282
283def staging_processfixme(fixme, target, recipesysroot, recipesysrootnative, d):
284 import subprocess
285
286 if not fixme:
287 return
288 cmd = "sed -e 's:^[^/]*/:%s/:g' %s | xargs sed -i -e 's:FIXMESTAGINGDIRTARGET:%s:g; s:FIXMESTAGINGDIRHOST:%s:g'" % (target, " ".join(fixme), recipesysroot, recipesysrootnative)
289 for fixmevar in ['PKGDATA_DIR']:
290 fixme_path = d.getVar(fixmevar)
291 cmd += " -e 's:FIXME_%s:%s:g'" % (fixmevar, fixme_path)
292 bb.note(cmd)
293 subprocess.check_call(cmd, shell=True)
294
295
296def staging_populate_sysroot_dir(targetsysroot, nativesysroot, native, d):
297 import glob
298 import subprocess
299
300 fixme = []
301 postinsts = []
302 stagingdir = d.getVar("STAGING_DIR")
303 if native:
304 pkgarchs = ['${BUILD_ARCH}', '${BUILD_ARCH}_*']
305 targetdir = nativesysroot
306 else:
307 pkgarchs = ['${MACHINE_ARCH}', '${TUNE_PKGARCH}', 'allarch']
308 targetdir = targetsysroot
309
310 bb.utils.mkdirhier(targetdir)
311 for pkgarch in pkgarchs:
312 for manifest in glob.glob(d.expand("${SSTATE_MANIFESTS}/manifest-%s-*.populate_sysroot" % pkgarch)):
313 if manifest.endswith("-initial.populate_sysroot"):
314 # skip glibc-initial and libgcc-initial due to file overlap
315 continue
316 tmanifest = targetdir + "/" + os.path.basename(manifest)
317 if os.path.exists(tmanifest):
318 continue
319 try:
320 os.link(manifest, tmanifest)
321 except OSError as err:
322 if err.errno == errno.EXDEV:
323 bb.utils.copyfile(manifest, tmanifest)
324 else:
325 raise
326 with open(manifest, "r") as f:
327 for l in f:
328 l = l.strip()
329 if l.endswith("/"):
330 staging_copydir(l, targetdir, stagingdir)
331 continue
332 staging_copyfile(l, targetdir, fixme, postinsts, stagingdir)
333
334 staging_processfixme(fixme, targetdir, targetsysroot, nativesysroot, d)
335 for p in postinsts:
336 subprocess.check_call(p, shell=True)
337
338#
339# Manifests here are complicated. The main sysroot area has the unpacked sstate
340# which us unrelocated and tracked by the main sstate manifests. Each recipe
341# specific sysroot has manifests for each dependency that is installed there.
342# The task hash is used to tell whether the data needs to be reinstalled. We
343# use a symlink to point to the currently installed hash. There is also a
344# "complete" stamp file which is used to mark if installation completed. If
345# something fails (e.g. a postinst), this won't get written and we would
346# remove and reinstall the dependency. This also means partially installed
347# dependencies should get cleaned up correctly.
348#
349
350python extend_recipe_sysroot() {
351 import copy
352 import subprocess
353
354 taskdepdata = d.getVar("BB_TASKDEPDATA", False)
355 mytaskname = d.getVar("BB_RUNTASK")
356 #bb.warn(str(taskdepdata))
357 pn = d.getVar("PN")
358
359 if mytaskname.endswith("_setscene"):
360 mytaskname = mytaskname.replace("_setscene", "")
361
362 start = None
363 configuredeps = []
364 for dep in taskdepdata:
365 data = taskdepdata[dep]
366 if data[1] == mytaskname and data[0] == pn:
367 start = dep
368 break
369 if start is None:
370 bb.fatal("Couldn't find ourself in BB_TASKDEPDATA?")
371
372 # We need to figure out which sysroot files we need to expose to this task.
373 # This needs to match what would get restored from sstate, which is controlled
374 # ultimately by calls from bitbake to setscene_depvalid().
375 # That function expects a setscene dependency tree. We build a dependency tree
376 # condensed to inter-sstate task dependencies, similar to that used by setscene
377 # tasks. We can then call into setscene_depvalid() and decide
378 # which dependencies we can "see" and should expose in the recipe specific sysroot.
379 setscenedeps = copy.deepcopy(taskdepdata)
380
381 start = set([start])
382
383 sstatetasks = d.getVar("SSTATETASKS").split()
384
385 def print_dep_tree(deptree):
386 data = ""
387 for dep in deptree:
388 deps = " " + "\n ".join(deptree[dep][3]) + "\n"
389 data = "%s:\n %s\n %s\n%s %s\n %s\n" % (deptree[dep][0], deptree[dep][1], deptree[dep][2], deps, deptree[dep][4], deptree[dep][5])
390 return data
391
392 #bb.note("Full dep tree is:\n%s" % print_dep_tree(taskdepdata))
393
394 #bb.note(" start2 is %s" % str(start))
395
396 # If start is an sstate task (like do_package) we need to add in its direct dependencies
397 # else the code below won't recurse into them.
398 for dep in set(start):
399 for dep2 in setscenedeps[dep][3]:
400 start.add(dep2)
401 start.remove(dep)
402
403 #bb.note(" start3 is %s" % str(start))
404
405 # Create collapsed do_populate_sysroot -> do_populate_sysroot tree
406 for dep in taskdepdata:
407 data = setscenedeps[dep]
408 if data[1] not in sstatetasks:
409 for dep2 in setscenedeps:
410 data2 = setscenedeps[dep2]
411 if dep in data2[3]:
412 data2[3].update(setscenedeps[dep][3])
413 data2[3].remove(dep)
414 if dep in start:
415 start.update(setscenedeps[dep][3])
416 start.remove(dep)
417 del setscenedeps[dep]
418
419 # Remove circular references
420 for dep in setscenedeps:
421 if dep in setscenedeps[dep][3]:
422 setscenedeps[dep][3].remove(dep)
423
424 #bb.note("Computed dep tree is:\n%s" % print_dep_tree(setscenedeps))
425 #bb.note(" start is %s" % str(start))
426
427 # Direct dependencies should be present and can be depended upon
428 for dep in set(start):
429 if setscenedeps[dep][1] == "do_populate_sysroot":
430 if dep not in configuredeps:
431 configuredeps.append(dep)
432 bb.note("Direct dependencies are %s" % str(configuredeps))
433 #bb.note(" or %s" % str(start))
434
435 # Call into setscene_depvalid for each sub-dependency and only copy sysroot files
436 # for ones that would be restored from sstate.
437 done = list(start)
438 next = list(start)
439 while next:
440 new = []
441 for dep in next:
442 data = setscenedeps[dep]
443 for datadep in data[3]:
444 if datadep in done:
445 continue
446 taskdeps = {}
447 taskdeps[dep] = setscenedeps[dep][:2]
448 taskdeps[datadep] = setscenedeps[datadep][:2]
449 retval = setscene_depvalid(datadep, taskdeps, [], d)
450 if retval:
451 bb.note("Skipping setscene dependency %s for installation into the sysroot" % datadep)
452 continue
453 done.append(datadep)
454 new.append(datadep)
455 if datadep not in configuredeps and setscenedeps[datadep][1] == "do_populate_sysroot":
456 configuredeps.append(datadep)
457 bb.note("Adding dependency on %s" % setscenedeps[datadep][0])
458 else:
459 bb.note("Following dependency on %s" % setscenedeps[datadep][0])
460 next = new
461
462 stagingdir = d.getVar("STAGING_DIR")
463 recipesysroot = d.getVar("RECIPE_SYSROOT")
464 recipesysrootnative = d.getVar("RECIPE_SYSROOT_NATIVE")
465 current_variant = d.getVar("BBEXTENDVARIANT")
466
467 # Detect bitbake -b usage
468 nodeps = d.getVar("BB_LIMITEDDEPS") or False
469 if nodeps:
470 lock = bb.utils.lockfile(recipesysroot + "/sysroot.lock")
471 staging_populate_sysroot_dir(recipesysroot, recipesysrootnative, True, d)
472 staging_populate_sysroot_dir(recipesysroot, recipesysrootnative, False, d)
473 bb.utils.unlockfile(lock)
474
475 depdir = recipesysrootnative + "/installeddeps"
476 bb.utils.mkdirhier(depdir)
477
478 lock = bb.utils.lockfile(recipesysroot + "/sysroot.lock")
479
480 fixme = {}
481 fixme[''] = []
482 fixme['native'] = []
483 postinsts = []
484 multilibs = {}
485
486 for dep in configuredeps:
487 c = setscenedeps[dep][0]
488 taskhash = setscenedeps[dep][5]
489 taskmanifest = depdir + "/" + c + "." + taskhash
490 if mytaskname in ["do_sdk_depends", "do_populate_sdk_ext"] and c.endswith("-initial"):
491 bb.note("Skipping initial setscene dependency %s for installation into the sysroot" % c)
492 continue
493 if os.path.exists(depdir + "/" + c):
494 lnk = os.readlink(depdir + "/" + c)
495 if lnk == c + "." + taskhash and os.path.exists(depdir + "/" + c + ".complete"):
496 bb.note("%s exists in sysroot, skipping" % c)
497 continue
498 else:
499 bb.note("%s exists in sysroot, but is stale (%s vs. %s), removing." % (c, lnk, c + "." + taskhash))
500 sstate_clean_manifest(depdir + "/" + lnk, d)
501 os.unlink(depdir + "/" + c)
502 elif os.path.lexists(depdir + "/" + c):
503 os.unlink(depdir + "/" + c)
504
505 os.symlink(c + "." + taskhash, depdir + "/" + c)
506
507 d2 = d
508 destsysroot = recipesysroot
509 variant = ''
510 if setscenedeps[dep][2].startswith("virtual:multilib"):
511 variant = setscenedeps[dep][2].split(":")[2]
512 if variant != current_variant:
513 if variant not in multilibs:
514 multilibs[variant] = get_multilib_datastore(variant, d)
515 d2 = multilibs[variant]
516 destsysroot = d2.getVar("RECIPE_SYSROOT")
517
518 native = False
519 if c.endswith("-native"):
520 manifest = d2.expand("${SSTATE_MANIFESTS}/manifest-${BUILD_ARCH}-%s.populate_sysroot" % c)
521 native = True
522 elif c.startswith("nativesdk-"):
523 manifest = d2.expand("${SSTATE_MANIFESTS}/manifest-${SDK_ARCH}_${SDK_OS}-%s.populate_sysroot" % c)
524 elif "-cross-" in c:
525 manifest = d2.expand("${SSTATE_MANIFESTS}/manifest-${BUILD_ARCH}_${TARGET_ARCH}-%s.populate_sysroot" % c)
526 native = True
527 elif "-crosssdk" in c:
528 manifest = d2.expand("${SSTATE_MANIFESTS}/manifest-${BUILD_ARCH}_${SDK_ARCH}_${SDK_OS}-%s.populate_sysroot" % c)
529 native = True
530 else:
531 manifest = d2.expand("${SSTATE_MANIFESTS}/manifest-${MACHINE_ARCH}-%s.populate_sysroot" % c)
532 if not os.path.exists(manifest):
533 manifest = d2.expand("${SSTATE_MANIFESTS}/manifest-${TUNE_PKGARCH}-%s.populate_sysroot" % c)
534 if not os.path.exists(manifest):
535 manifest = d2.expand("${SSTATE_MANIFESTS}/manifest-allarch-%s.populate_sysroot" % c)
536 if not os.path.exists(manifest):
537 bb.warn("Manifest %s not found?" % manifest)
538 else:
539 with open(manifest, "r") as f, open(taskmanifest, 'w') as m:
540 for l in f:
541 l = l.strip()
542 if l.endswith("/"):
543 if native:
544 dest = staging_copydir(l, recipesysrootnative, stagingdir)
545 else:
546 dest = staging_copydir(l, destsysroot, stagingdir)
547 continue
548 if native:
549 dest = staging_copyfile(l, recipesysrootnative, fixme['native'], postinsts, stagingdir)
550 else:
551 dest = staging_copyfile(l, destsysroot, fixme[''], postinsts, stagingdir)
552 if dest:
553 m.write(dest + "\n")
554
555 for f in fixme:
556 if f == '':
557 staging_processfixme(fixme[f], recipesysroot, recipesysroot, recipesysrootnative, d)
558 elif f == 'native':
559 staging_processfixme(fixme[f], recipesysrootnative, recipesysroot, recipesysrootnative, d)
560 else:
561 staging_processfixme(fixme[f], multilibs[f].getVar("RECIPE_SYSROOT"), recipesysroot, recipesysrootnative, d)
562
563 for p in postinsts:
564 subprocess.check_call(p, shell=True)
565
566 for dep in configuredeps:
567 c = setscenedeps[dep][0]
568 open(depdir + "/" + c + ".complete", "w").close()
569
570 bb.utils.unlockfile(lock)
571}
572extend_recipe_sysroot[vardepsexclude] += "MACHINE SDK_ARCH BUILD_ARCH SDK_OS BB_TASKDEPDATA"
573
574python do_prepare_recipe_sysroot () {
575 bb.build.exec_func("extend_recipe_sysroot", d)
576}
577addtask do_prepare_recipe_sysroot before do_configure after do_fetch
578
579# Clean out the recipe specific sysroots before do_fetch
580do_fetch[cleandirs] += "${RECIPE_SYSROOT} ${RECIPE_SYSROOT_NATIVE}"
581
582python staging_taskhandler() {
583 bbtasks = e.tasklist
584 for task in bbtasks:
585 deps = d.getVarFlag(task, "depends")
586 if deps and "populate_sysroot" in deps:
587 d.appendVarFlag(task, "prefuncs", " extend_recipe_sysroot")
588}
589staging_taskhandler[eventmask] = "bb.event.RecipeTaskPreProcess"
590addhandler staging_taskhandler
246 591