1# 2# Copyright OpenEmbedded Contributors 3# 4# SPDX-License-Identifier: MIT 5# 6 7# These directories will be staged in the sysroot 8SYSROOT_DIRS = " \ 9 ${includedir} \ 10 ${libdir} \ 11 ${base_libdir} \ 12 ${nonarch_base_libdir} \ 13 ${datadir} \ 14 /sysroot-only \ 15" 16 17# These directories are also staged in the sysroot when they contain files that 18# are usable on the build system 19SYSROOT_DIRS_NATIVE = " \ 20 ${bindir} \ 21 ${sbindir} \ 22 ${base_bindir} \ 23 ${base_sbindir} \ 24 ${libexecdir} \ 25 ${sysconfdir} \ 26 ${localstatedir} \ 27" 28SYSROOT_DIRS:append:class-native = " ${SYSROOT_DIRS_NATIVE}" 29SYSROOT_DIRS:append:class-cross = " ${SYSROOT_DIRS_NATIVE}" 30SYSROOT_DIRS:append:class-crosssdk = " ${SYSROOT_DIRS_NATIVE}" 31 32# These directories will not be staged in the sysroot 33SYSROOT_DIRS_IGNORE = " \ 34 ${mandir} \ 35 ${docdir} \ 36 ${infodir} \ 37 ${datadir}/X11/locale \ 38 ${datadir}/applications \ 39 ${datadir}/bash-completion \ 40 ${datadir}/fonts \ 41 ${datadir}/gtk-doc/html \ 42 ${datadir}/installed-tests \ 43 ${datadir}/locale \ 44 ${datadir}/pixmaps \ 45 ${datadir}/terminfo \ 46 ${libdir}/${BPN}/ptest \ 47" 48 49sysroot_stage_dir() { 50 src="$1" 51 dest="$2" 52 # if the src doesn't exist don't do anything 53 if [ ! -d "$src" ]; then 54 return 55 fi 56 57 mkdir -p "$dest" 58 rdest=$(realpath --relative-to="$src" "$dest") 59 ( 60 cd $src 61 find . -print0 | cpio --null -pdlu $rdest 62 ) 63} 64 65sysroot_stage_dirs() { 66 from="$1" 67 to="$2" 68 69 for dir in ${SYSROOT_DIRS}; do 70 sysroot_stage_dir "$from$dir" "$to$dir" 71 done 72 73 # Remove directories we do not care about 74 for dir in ${SYSROOT_DIRS_IGNORE}; do 75 rm -rf "$to$dir" 76 done 77} 78 79sysroot_stage_all() { 80 sysroot_stage_dirs ${D} ${SYSROOT_DESTDIR} 81} 82 83python sysroot_strip () { 84 inhibit_sysroot = d.getVar('INHIBIT_SYSROOT_STRIP') 85 if inhibit_sysroot and oe.types.boolean(inhibit_sysroot): 86 return 87 88 dstdir = d.getVar('SYSROOT_DESTDIR') 89 pn = d.getVar('PN') 90 libdir = d.getVar("libdir") 91 base_libdir = d.getVar("base_libdir") 92 qa_already_stripped = 'already-stripped' in (d.getVar('INSANE_SKIP:' + pn) or "").split() 93 strip_cmd = d.getVar("STRIP") 94 95 max_process = oe.utils.get_bb_number_threads(d) 96 oe.package.strip_execs(pn, dstdir, strip_cmd, libdir, base_libdir, max_process, 97 qa_already_stripped=qa_already_stripped) 98} 99 100do_populate_sysroot[dirs] = "${SYSROOT_DESTDIR}" 101 102addtask populate_sysroot after do_install 103 104SYSROOT_PREPROCESS_FUNCS ?= "" 105SYSROOT_DESTDIR = "${WORKDIR}/sysroot-destdir" 106 107python do_populate_sysroot () { 108 # SYSROOT 'version' 2 109 bb.build.exec_func("sysroot_stage_all", d) 110 bb.build.exec_func("sysroot_strip", d) 111 for f in (d.getVar('SYSROOT_PREPROCESS_FUNCS') or '').split(): 112 bb.build.exec_func(f, d) 113 pn = d.getVar("PN") 114 multiprov = d.getVar("BB_MULTI_PROVIDER_ALLOWED").split() 115 provdir = d.expand("${SYSROOT_DESTDIR}${base_prefix}/sysroot-providers/") 116 bb.utils.mkdirhier(provdir) 117 for p in d.getVar("PROVIDES").split(): 118 if p in multiprov: 119 continue 120 p = p.replace("/", "_") 121 with open(provdir + p, "w") as f: 122 f.write(pn) 123} 124 125do_populate_sysroot[vardeps] += "${SYSROOT_PREPROCESS_FUNCS}" 126do_populate_sysroot[vardepsexclude] += "BB_MULTI_PROVIDER_ALLOWED" 127 128POPULATESYSROOTDEPS = "" 129POPULATESYSROOTDEPS:class-target = "virtual/${HOST_PREFIX}binutils:do_populate_sysroot" 130POPULATESYSROOTDEPS:class-nativesdk = "virtual/${HOST_PREFIX}binutils:do_populate_sysroot" 131do_populate_sysroot[depends] += "${POPULATESYSROOTDEPS}" 132 133SSTATETASKS += "do_populate_sysroot" 134do_populate_sysroot[cleandirs] = "${SYSROOT_DESTDIR}" 135do_populate_sysroot[sstate-inputdirs] = "${SYSROOT_DESTDIR}" 136do_populate_sysroot[sstate-outputdirs] = "${COMPONENTS_DIR}/${PACKAGE_ARCH}/${PN}" 137do_populate_sysroot[sstate-fixmedir] = "${COMPONENTS_DIR}/${PACKAGE_ARCH}/${PN}" 138 139python do_populate_sysroot_setscene () { 140 sstate_setscene(d) 141} 142addtask do_populate_sysroot_setscene 143 144def staging_copyfile(c, target, dest, postinsts, seendirs): 145 import errno 146 147 destdir = os.path.dirname(dest) 148 if destdir not in seendirs: 149 bb.utils.mkdirhier(destdir) 150 seendirs.add(destdir) 151 if "/usr/bin/postinst-" in c: 152 postinsts.append(dest) 153 if os.path.islink(c): 154 linkto = os.readlink(c) 155 if os.path.lexists(dest): 156 if not os.path.islink(dest): 157 raise OSError(errno.EEXIST, "Link %s already exists as a file" % dest, dest) 158 if os.readlink(dest) == linkto: 159 return dest 160 raise OSError(errno.EEXIST, "Link %s already exists to a different location? (%s vs %s)" % (dest, os.readlink(dest), linkto), dest) 161 os.symlink(linkto, dest) 162 #bb.warn(c) 163 else: 164 try: 165 os.link(c, dest) 166 except OSError as err: 167 if err.errno == errno.EXDEV: 168 bb.utils.copyfile(c, dest) 169 else: 170 raise 171 return dest 172 173def staging_copydir(c, target, dest, seendirs): 174 if dest not in seendirs: 175 bb.utils.mkdirhier(dest) 176 seendirs.add(dest) 177 178def staging_processfixme(fixme, target, recipesysroot, recipesysrootnative, d): 179 import subprocess 180 181 if not fixme: 182 return 183 cmd = "sed -e 's:^[^/]*/:%s/:g' %s | xargs sed -i -e 's:FIXMESTAGINGDIRTARGET:%s:g; s:FIXMESTAGINGDIRHOST:%s:g'" % (target, " ".join(fixme), recipesysroot, recipesysrootnative) 184 for fixmevar in ['PSEUDO_SYSROOT', 'HOSTTOOLS_DIR', 'PKGDATA_DIR', 'PSEUDO_LOCALSTATEDIR', 'LOGFIFO']: 185 fixme_path = d.getVar(fixmevar) 186 cmd += " -e 's:FIXME_%s:%s:g'" % (fixmevar, fixme_path) 187 bb.debug(2, cmd) 188 subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT) 189 190 191def staging_populate_sysroot_dir(targetsysroot, nativesysroot, native, d): 192 import glob 193 import subprocess 194 import errno 195 196 fixme = [] 197 postinsts = [] 198 seendirs = set() 199 stagingdir = d.getVar("STAGING_DIR") 200 if native: 201 pkgarchs = ['${BUILD_ARCH}', '${BUILD_ARCH}_*'] 202 targetdir = nativesysroot 203 else: 204 pkgarchs = ['${MACHINE_ARCH}'] 205 pkgarchs = pkgarchs + list(reversed(d.getVar("PACKAGE_EXTRA_ARCHS").split())) 206 pkgarchs.append('allarch') 207 targetdir = targetsysroot 208 209 bb.utils.mkdirhier(targetdir) 210 for pkgarch in pkgarchs: 211 for manifest in glob.glob(d.expand("${SSTATE_MANIFESTS}/manifest-%s-*.populate_sysroot" % pkgarch)): 212 if manifest.endswith("-initial.populate_sysroot"): 213 # skip libgcc-initial due to file overlap 214 continue 215 if not native and (manifest.endswith("-native.populate_sysroot") or "nativesdk-" in manifest): 216 continue 217 if native and not (manifest.endswith("-native.populate_sysroot") or manifest.endswith("-cross.populate_sysroot") or "-cross-" in manifest): 218 continue 219 tmanifest = targetdir + "/" + os.path.basename(manifest) 220 if os.path.exists(tmanifest): 221 continue 222 try: 223 os.link(manifest, tmanifest) 224 except OSError as err: 225 if err.errno == errno.EXDEV: 226 bb.utils.copyfile(manifest, tmanifest) 227 else: 228 raise 229 with open(manifest, "r") as f: 230 for l in f: 231 l = l.strip() 232 if l.endswith("/fixmepath"): 233 fixme.append(l) 234 continue 235 if l.endswith("/fixmepath.cmd"): 236 continue 237 dest = l.replace(stagingdir, "") 238 dest = targetdir + "/" + "/".join(dest.split("/")[3:]) 239 if l.endswith("/"): 240 staging_copydir(l, targetdir, dest, seendirs) 241 continue 242 try: 243 staging_copyfile(l, targetdir, dest, postinsts, seendirs) 244 except FileExistsError: 245 continue 246 247 staging_processfixme(fixme, targetdir, targetsysroot, nativesysroot, d) 248 for p in sorted(postinsts): 249 bb.note("Running postinst {}, output:\n{}".format(p, subprocess.check_output(p, shell=True, stderr=subprocess.STDOUT))) 250 251# 252# Manifests here are complicated. The main sysroot area has the unpacked sstate 253# which us unrelocated and tracked by the main sstate manifests. Each recipe 254# specific sysroot has manifests for each dependency that is installed there. 255# The task hash is used to tell whether the data needs to be reinstalled. We 256# use a symlink to point to the currently installed hash. There is also a 257# "complete" stamp file which is used to mark if installation completed. If 258# something fails (e.g. a postinst), this won't get written and we would 259# remove and reinstall the dependency. This also means partially installed 260# dependencies should get cleaned up correctly. 261# 262 263python extend_recipe_sysroot() { 264 import copy 265 import subprocess 266 import errno 267 import collections 268 import glob 269 270 taskdepdata = d.getVar("BB_TASKDEPDATA", False) 271 mytaskname = d.getVar("BB_RUNTASK") 272 if mytaskname.endswith("_setscene"): 273 mytaskname = mytaskname.replace("_setscene", "") 274 workdir = d.getVar("WORKDIR") 275 #bb.warn(str(taskdepdata)) 276 pn = d.getVar("PN") 277 stagingdir = d.getVar("STAGING_DIR") 278 sharedmanifests = d.getVar("COMPONENTS_DIR") + "/manifests" 279 # only needed by multilib cross-canadian since it redefines RECIPE_SYSROOT 280 manifestprefix = d.getVar("RECIPE_SYSROOT_MANIFEST_SUBDIR") 281 if manifestprefix: 282 sharedmanifests = sharedmanifests + "/" + manifestprefix 283 recipesysroot = d.getVar("RECIPE_SYSROOT") 284 recipesysrootnative = d.getVar("RECIPE_SYSROOT_NATIVE") 285 286 # Detect bitbake -b usage 287 nodeps = d.getVar("BB_LIMITEDDEPS") or False 288 if nodeps: 289 lock = bb.utils.lockfile(recipesysroot + "/sysroot.lock") 290 staging_populate_sysroot_dir(recipesysroot, recipesysrootnative, True, d) 291 staging_populate_sysroot_dir(recipesysroot, recipesysrootnative, False, d) 292 bb.utils.unlockfile(lock) 293 return 294 295 start = None 296 configuredeps = [] 297 owntaskdeps = [] 298 for dep in taskdepdata: 299 data = taskdepdata[dep] 300 if data[1] == mytaskname and data[0] == pn: 301 start = dep 302 elif data[0] == pn: 303 owntaskdeps.append(data[1]) 304 if start is None: 305 bb.fatal("Couldn't find ourself in BB_TASKDEPDATA?") 306 307 # We need to figure out which sysroot files we need to expose to this task. 308 # This needs to match what would get restored from sstate, which is controlled 309 # ultimately by calls from bitbake to setscene_depvalid(). 310 # That function expects a setscene dependency tree. We build a dependency tree 311 # condensed to inter-sstate task dependencies, similar to that used by setscene 312 # tasks. We can then call into setscene_depvalid() and decide 313 # which dependencies we can "see" and should expose in the recipe specific sysroot. 314 setscenedeps = copy.deepcopy(taskdepdata) 315 316 start = set([start]) 317 318 sstatetasks = d.getVar("SSTATETASKS").split() 319 # Add recipe specific tasks referenced by setscene_depvalid() 320 sstatetasks.append("do_stash_locale") 321 sstatetasks.append("do_deploy") 322 323 def print_dep_tree(deptree): 324 data = "" 325 for dep in deptree: 326 deps = " " + "\n ".join(deptree[dep][3]) + "\n" 327 data = 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]) 328 return data 329 330 #bb.note("Full dep tree is:\n%s" % print_dep_tree(taskdepdata)) 331 332 #bb.note(" start2 is %s" % str(start)) 333 334 # If start is an sstate task (like do_package) we need to add in its direct dependencies 335 # else the code below won't recurse into them. 336 for dep in set(start): 337 for dep2 in setscenedeps[dep][3]: 338 start.add(dep2) 339 start.remove(dep) 340 341 #bb.note(" start3 is %s" % str(start)) 342 343 # Create collapsed do_populate_sysroot -> do_populate_sysroot tree 344 for dep in taskdepdata: 345 data = setscenedeps[dep] 346 if data[1] not in sstatetasks: 347 for dep2 in setscenedeps: 348 data2 = setscenedeps[dep2] 349 if dep in data2[3]: 350 data2[3].update(setscenedeps[dep][3]) 351 data2[3].remove(dep) 352 if dep in start: 353 start.update(setscenedeps[dep][3]) 354 start.remove(dep) 355 del setscenedeps[dep] 356 357 # Remove circular references 358 for dep in setscenedeps: 359 if dep in setscenedeps[dep][3]: 360 setscenedeps[dep][3].remove(dep) 361 362 #bb.note("Computed dep tree is:\n%s" % print_dep_tree(setscenedeps)) 363 #bb.note(" start is %s" % str(start)) 364 365 # Direct dependencies should be present and can be depended upon 366 for dep in sorted(set(start)): 367 if setscenedeps[dep][1] == "do_populate_sysroot": 368 if dep not in configuredeps: 369 configuredeps.append(dep) 370 bb.note("Direct dependencies are %s" % str(configuredeps)) 371 #bb.note(" or %s" % str(start)) 372 373 msgbuf = [] 374 # Call into setscene_depvalid for each sub-dependency and only copy sysroot files 375 # for ones that would be restored from sstate. 376 done = list(start) 377 next = list(start) 378 while next: 379 new = [] 380 for dep in next: 381 data = setscenedeps[dep] 382 for datadep in data[3]: 383 if datadep in done: 384 continue 385 taskdeps = {} 386 taskdeps[dep] = setscenedeps[dep][:2] 387 taskdeps[datadep] = setscenedeps[datadep][:2] 388 retval = setscene_depvalid(datadep, taskdeps, [], d, msgbuf) 389 if retval: 390 msgbuf.append("Skipping setscene dependency %s for installation into the sysroot" % datadep) 391 continue 392 done.append(datadep) 393 new.append(datadep) 394 if datadep not in configuredeps and setscenedeps[datadep][1] == "do_populate_sysroot": 395 configuredeps.append(datadep) 396 msgbuf.append("Adding dependency on %s" % setscenedeps[datadep][0]) 397 else: 398 msgbuf.append("Following dependency on %s" % setscenedeps[datadep][0]) 399 next = new 400 401 # This logging is too verbose for day to day use sadly 402 #bb.debug(2, "\n".join(msgbuf)) 403 404 depdir = recipesysrootnative + "/installeddeps" 405 bb.utils.mkdirhier(depdir) 406 bb.utils.mkdirhier(sharedmanifests) 407 408 lock = bb.utils.lockfile(recipesysroot + "/sysroot.lock") 409 410 fixme = {} 411 seendirs = set() 412 postinsts = [] 413 multilibs = {} 414 manifests = {} 415 # All files that we're going to be installing, to find conflicts. 416 fileset = {} 417 418 invalidate_tasks = set() 419 for f in os.listdir(depdir): 420 removed = [] 421 if not f.endswith(".complete"): 422 continue 423 f = depdir + "/" + f 424 if os.path.islink(f) and not os.path.exists(f): 425 bb.note("%s no longer exists, removing from sysroot" % f) 426 lnk = os.readlink(f.replace(".complete", "")) 427 sstate_clean_manifest(depdir + "/" + lnk, d, canrace=True, prefix=workdir) 428 os.unlink(f) 429 os.unlink(f.replace(".complete", "")) 430 removed.append(os.path.basename(f.replace(".complete", ""))) 431 432 # If we've removed files from the sysroot above, the task that installed them may still 433 # have a stamp file present for the task. This is probably invalid right now but may become 434 # valid again if the user were to change configuration back for example. Since we've removed 435 # the files a task might need, remove the stamp file too to force it to rerun. 436 # YOCTO #14790 437 if removed: 438 for i in glob.glob(depdir + "/index.*"): 439 if i.endswith("." + mytaskname): 440 continue 441 with open(i, "r") as f: 442 for l in f: 443 if l.startswith("TaskDeps:"): 444 continue 445 l = l.strip() 446 if l in removed: 447 invalidate_tasks.add(i.rsplit(".", 1)[1]) 448 break 449 for t in invalidate_tasks: 450 bb.note("Invalidating stamps for task %s" % t) 451 bb.build.clean_stamp(t, d) 452 453 installed = [] 454 for dep in configuredeps: 455 c = setscenedeps[dep][0] 456 if mytaskname in ["do_sdk_depends", "do_populate_sdk_ext"] and c.endswith("-initial"): 457 bb.note("Skipping initial setscene dependency %s for installation into the sysroot" % c) 458 continue 459 installed.append(c) 460 461 # We want to remove anything which this task previously installed but is no longer a dependency 462 taskindex = depdir + "/" + "index." + mytaskname 463 if os.path.exists(taskindex): 464 potential = [] 465 with open(taskindex, "r") as f: 466 for l in f: 467 l = l.strip() 468 if l not in installed: 469 fl = depdir + "/" + l 470 if not os.path.exists(fl): 471 # Was likely already uninstalled 472 continue 473 potential.append(l) 474 # We need to ensure no other task needs this dependency. We hold the sysroot 475 # lock so we ca search the indexes to check 476 if potential: 477 for i in glob.glob(depdir + "/index.*"): 478 if i.endswith("." + mytaskname): 479 continue 480 with open(i, "r") as f: 481 for l in f: 482 if l.startswith("TaskDeps:"): 483 prevtasks = l.split()[1:] 484 if mytaskname in prevtasks: 485 # We're a dependency of this task so we can clear items out the sysroot 486 break 487 l = l.strip() 488 if l in potential: 489 potential.remove(l) 490 for l in potential: 491 fl = depdir + "/" + l 492 bb.note("Task %s no longer depends on %s, removing from sysroot" % (mytaskname, l)) 493 lnk = os.readlink(fl) 494 sstate_clean_manifest(depdir + "/" + lnk, d, canrace=True, prefix=workdir) 495 os.unlink(fl) 496 os.unlink(fl + ".complete") 497 498 msg_exists = [] 499 msg_adding = [] 500 501 # Handle all removals first since files may move between recipes 502 for dep in configuredeps: 503 c = setscenedeps[dep][0] 504 if c not in installed: 505 continue 506 taskhash = setscenedeps[dep][5] 507 taskmanifest = depdir + "/" + c + "." + taskhash 508 509 if os.path.exists(depdir + "/" + c): 510 lnk = os.readlink(depdir + "/" + c) 511 if lnk == c + "." + taskhash and os.path.exists(depdir + "/" + c + ".complete"): 512 continue 513 else: 514 bb.note("%s exists in sysroot, but is stale (%s vs. %s), removing." % (c, lnk, c + "." + taskhash)) 515 sstate_clean_manifest(depdir + "/" + lnk, d, canrace=True, prefix=workdir) 516 os.unlink(depdir + "/" + c) 517 if os.path.lexists(depdir + "/" + c + ".complete"): 518 os.unlink(depdir + "/" + c + ".complete") 519 elif os.path.lexists(depdir + "/" + c): 520 os.unlink(depdir + "/" + c) 521 522 binfiles = {} 523 # Now handle installs 524 for dep in sorted(configuredeps): 525 c = setscenedeps[dep][0] 526 if c not in installed: 527 continue 528 taskhash = setscenedeps[dep][5] 529 taskmanifest = depdir + "/" + c + "." + taskhash 530 531 if os.path.exists(depdir + "/" + c): 532 lnk = os.readlink(depdir + "/" + c) 533 if lnk == c + "." + taskhash and os.path.exists(depdir + "/" + c + ".complete"): 534 msg_exists.append(c) 535 continue 536 537 msg_adding.append(c) 538 539 os.symlink(c + "." + taskhash, depdir + "/" + c) 540 541 manifest, d2 = oe.sstatesig.find_sstate_manifest(c, setscenedeps[dep][2], "populate_sysroot", d, multilibs) 542 if d2 is not d: 543 # If we don't do this, the recipe sysroot will be placed in the wrong WORKDIR for multilibs 544 # We need a consistent WORKDIR for the image 545 d2.setVar("WORKDIR", d.getVar("WORKDIR")) 546 destsysroot = d2.getVar("RECIPE_SYSROOT") 547 # We put allarch recipes into the default sysroot 548 if manifest and "allarch" in manifest: 549 destsysroot = d.getVar("RECIPE_SYSROOT") 550 551 native = False 552 if c.endswith("-native") or "-cross-" in c or "-crosssdk" in c: 553 native = True 554 555 if manifest: 556 newmanifest = collections.OrderedDict() 557 targetdir = destsysroot 558 if native: 559 targetdir = recipesysrootnative 560 if targetdir not in fixme: 561 fixme[targetdir] = [] 562 fm = fixme[targetdir] 563 564 with open(manifest, "r") as f: 565 manifests[dep] = manifest 566 for l in f: 567 l = l.strip() 568 if l.endswith("/fixmepath"): 569 fm.append(l) 570 continue 571 if l.endswith("/fixmepath.cmd"): 572 continue 573 dest = l.replace(stagingdir, "") 574 dest = "/" + "/".join(dest.split("/")[3:]) 575 newmanifest[l] = targetdir + dest 576 577 # Check if files have already been installed by another 578 # recipe and abort if they have, explaining what recipes are 579 # conflicting. 580 hashname = targetdir + dest 581 if not hashname.endswith("/"): 582 if hashname in fileset: 583 bb.fatal("The file %s is installed by both %s and %s, aborting" % (dest, c, fileset[hashname])) 584 else: 585 fileset[hashname] = c 586 587 # Having multiple identical manifests in each sysroot eats diskspace so 588 # create a shared pool of them and hardlink if we can. 589 # We create the manifest in advance so that if something fails during installation, 590 # or the build is interrupted, subsequent exeuction can cleanup. 591 sharedm = sharedmanifests + "/" + os.path.basename(taskmanifest) 592 if not os.path.exists(sharedm): 593 smlock = bb.utils.lockfile(sharedm + ".lock") 594 # Can race here. You'd think it just means we may not end up with all copies hardlinked to each other 595 # but python can lose file handles so we need to do this under a lock. 596 if not os.path.exists(sharedm): 597 with open(sharedm, 'w') as m: 598 for l in newmanifest: 599 dest = newmanifest[l] 600 m.write(dest.replace(workdir + "/", "") + "\n") 601 bb.utils.unlockfile(smlock) 602 try: 603 os.link(sharedm, taskmanifest) 604 except OSError as err: 605 if err.errno == errno.EXDEV: 606 bb.utils.copyfile(sharedm, taskmanifest) 607 else: 608 raise 609 # Finally actually install the files 610 for l in newmanifest: 611 dest = newmanifest[l] 612 if l.endswith("/"): 613 staging_copydir(l, targetdir, dest, seendirs) 614 continue 615 if "/bin/" in l or "/sbin/" in l: 616 # defer /*bin/* files until last in case they need libs 617 binfiles[l] = (targetdir, dest) 618 else: 619 staging_copyfile(l, targetdir, dest, postinsts, seendirs) 620 621 # Handle deferred binfiles 622 for l in binfiles: 623 (targetdir, dest) = binfiles[l] 624 staging_copyfile(l, targetdir, dest, postinsts, seendirs) 625 626 bb.note("Installed into sysroot: %s" % str(msg_adding)) 627 bb.note("Skipping as already exists in sysroot: %s" % str(msg_exists)) 628 629 for f in fixme: 630 staging_processfixme(fixme[f], f, recipesysroot, recipesysrootnative, d) 631 632 for p in sorted(postinsts): 633 bb.note("Running postinst {}, output:\n{}".format(p, subprocess.check_output(p, shell=True, stderr=subprocess.STDOUT))) 634 635 for dep in manifests: 636 c = setscenedeps[dep][0] 637 os.symlink(manifests[dep], depdir + "/" + c + ".complete") 638 639 with open(taskindex, "w") as f: 640 f.write("TaskDeps: " + " ".join(owntaskdeps) + "\n") 641 for l in sorted(installed): 642 f.write(l + "\n") 643 644 bb.utils.unlockfile(lock) 645} 646extend_recipe_sysroot[vardepsexclude] += "MACHINE_ARCH PACKAGE_EXTRA_ARCHS SDK_ARCH BUILD_ARCH SDK_OS BB_TASKDEPDATA" 647 648do_prepare_recipe_sysroot[deptask] = "do_populate_sysroot" 649python do_prepare_recipe_sysroot () { 650 bb.build.exec_func("extend_recipe_sysroot", d) 651} 652addtask do_prepare_recipe_sysroot before do_configure after do_fetch 653 654python staging_taskhandler() { 655 bbtasks = e.tasklist 656 for task in bbtasks: 657 deps = d.getVarFlag(task, "depends") 658 if task != 'do_prepare_recipe_sysroot' and (task == "do_configure" or (deps and "populate_sysroot" in deps)): 659 d.prependVarFlag(task, "prefuncs", "extend_recipe_sysroot ") 660} 661staging_taskhandler[eventmask] = "bb.event.RecipeTaskPreProcess" 662addhandler staging_taskhandler 663 664 665# 666# Target build output, stored in do_populate_sysroot or do_package can depend 667# not only upon direct dependencies but also indirect ones. A good example is 668# linux-libc-headers. The toolchain depends on this but most target recipes do 669# not. There are some headers which are not used by the toolchain build and do 670# not change the toolchain task output, hence the task hashes can change without 671# changing the sysroot output of that recipe yet they can influence others. 672# 673# A specific example is rtc.h which can change rtcwake.c in util-linux but is not 674# used in the glibc or gcc build. To account for this, we need to account for the 675# populate_sysroot hashes in the task output hashes. 676# 677python target_add_sysroot_deps () { 678 current_task = "do_" + d.getVar("BB_CURRENTTASK") 679 if current_task not in ["do_populate_sysroot", "do_package"]: 680 return 681 682 pn = d.getVar("PN") 683 if pn.endswith("-native"): 684 return 685 686 taskdepdata = d.getVar("BB_TASKDEPDATA", False) 687 deps = {} 688 for dep in taskdepdata.values(): 689 if dep[1] == "do_populate_sysroot" and not dep[0].endswith(("-native", "-initial")) and "-cross-" not in dep[0] and dep[0] != pn: 690 deps[dep[0]] = dep[6] 691 692 d.setVar("HASHEQUIV_EXTRA_SIGDATA", "\n".join("%s: %s" % (k, deps[k]) for k in sorted(deps.keys()))) 693} 694SSTATECREATEFUNCS += "target_add_sysroot_deps" 695 696