blob: 3678a1b4415f02d7c7b97d7aadbf2a81833e2da2 [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
Andrew Geissler220dafd2023-10-04 10:18:08 -050095 max_process = oe.utils.get_bb_number_threads(d)
96 oe.package.strip_execs(pn, dstdir, strip_cmd, libdir, base_libdir, max_process,
Patrick Williams92b42cb2022-09-03 06:53:57 -050097 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 = ""
Andrew Geissler028142b2023-05-05 11:29:21 -0500129POPULATESYSROOTDEPS:class-target = "virtual/${HOST_PREFIX}binutils:do_populate_sysroot"
130POPULATESYSROOTDEPS:class-nativesdk = "virtual/${HOST_PREFIX}binutils:do_populate_sysroot"
Patrick Williams92b42cb2022-09-03 06:53:57 -0500131do_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)
Patrick Williams39653562024-03-01 08:54:02 -0600248 for p in sorted(postinsts):
Patrick Williams73bd93f2024-02-20 08:07:48 -0600249 bb.note("Running postinst {}, output:\n{}".format(p, subprocess.check_output(p, shell=True, stderr=subprocess.STDOUT)))
Patrick Williams92b42cb2022-09-03 06:53:57 -0500250
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"
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500279 # 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
Patrick Williams92b42cb2022-09-03 06:53:57 -0500283 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
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600524 for dep in sorted(configuredeps):
Patrick Williams92b42cb2022-09-03 06:53:57 -0500525 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
Patrick Williams39653562024-03-01 08:54:02 -0600632 for p in sorted(postinsts):
Patrick Williams73bd93f2024-02-20 08:07:48 -0600633 bb.note("Running postinst {}, output:\n{}".format(p, subprocess.check_output(p, shell=True, stderr=subprocess.STDOUT)))
Patrick Williams92b42cb2022-09-03 06:53:57 -0500634
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")
Patrick Williamse760df82023-05-26 11:10:49 -0500658 if task != 'do_prepare_recipe_sysroot' and (task == "do_configure" or (deps and "populate_sysroot" in deps)):
Patrick Williams92b42cb2022-09-03 06:53:57 -0500659 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