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