Re: [meta-virtualization] [PATCH 2/2] image-oci: drop *-initial sysroot deps in do_image_oci to avoid libgcc collision

Bruce Ashfield <[email protected]> Tue, 28 Jul 2026 20:17:17 -0700 (PDT)
Newsgroups org.yoctoproject.lists.meta-virtualization
Message-ID <[email protected]>
Reviewed but holding this one for a bit. Two things:

First, on the fix mechanism: the analysis in the commit message is
convincing and matches what oe-core already does for do_sdk_depends
and do_populate_sdk_ext at staging.bbclass:457 (same "*-initial" skip,
same reason).

If that list of tasks was extendible, we could add do_image_oci to it,
but Richard wouldn't think it was a good idea if I tried to bury a
meta-virt task into that list :)

BitBake's python-function :prepend/:append doesn't help either -- the
mid-loop condition operates on setscenedeps built inside the function,
not on anything we could pre-filter via a prepend body. Prefunc +
BB_TASKDEPDATA mutation looks like the only path that won't need to
be updated as bitbake/oe-core change.

I'm testing a smaller-footprint variant of the same approach -- same
idea, same event-handler attachment, roughly 15 lines without the
deep-copy (setVar with a fresh dict is enough since
extend_recipe_sysroot re-reads BB_TASKDEPDATA on each entry).
Body/mechanism identical to yours; the trim is stylistic.

Second, and this is what's actually blocking: I haven't managed
to reproduce the raw abort locally. From your cover letter, it
doesn't sound like you are there yet either ? Without a repro that
fails on stock and passes with the fix, all we've got is "the code
path runs and does what the comment says it does" -- which is true
but doesn't prove the payoff. Eventually that might be enough, but
I'd like to try a bit more.

Two questions to unblock:

1) Can you share the specific recipe (or the DEPENDS shape) from
   the downstream build where you hit this deterministically?
   Something along the lines of a multilayer packages: layer
   pulling a from-source-compiled library with a boost-ish
   DEPENDS, if I'm reading your cover right, but I'd rather work
   from your actual trigger than guess.

2) Was there anything else in that build environment worth
   knowing -- IMAGE_PKGTYPE pin, non-default MACHINE, a specific
   PACKAGECONFIG that pulled in one of the *-initial-adjacent
   recipes? Anything that narrows the search.

I'll try a boost-multilayer-packages recipe over several clean-sstate
cycles in the meantime and report back either way.  Once we have that,
merging this (in whichever variant) is easy.

Below is the shortened variant I mentioned -- meant to fully replace
the two python blocks + the comment header in your 2/2, drop-in on the
same insertion point in image-oci.bbclass. Same mechanism as yours:
event handler on RecipeTaskPreProcess attaches a prefunc to
do_image_oci that filters *-initial do_populate_sysroot nodes out of
BB_TASKDEPDATA before extend_recipe_sysroot walks it. Differences are
stylistic -- no deep-copy (dict comprehension builds a fresh dict
directly), set comprehension for the drop set, comment made smaller.

Not requesting a v2 on this; posting so you can try it against your
downstream trigger and see if it holds up the same way your original
does.

# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D
# Work around libgcc vs libgcc-initial sysroot collision in do_image_oci
# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D
#
# do_image_oci[depends] contains "...:do_populate_sysroot" entries, so
# oe-core's staging_taskhandler auto-attaches extend_recipe_sysroot as a
# prefunc. That walk exposes the full transitive populate_sysroot closure
# into this recipe's private sysroot -- including both libgcc and
# libgcc-initial, which collide on crtbegin.o.
#
# oe-core's SSTATE_EXCLUDEDEPS_SYSROOT (".*->.*-initial.*") is gated on
# the consuming task being do_populate_sysroot (see setscene_depvalid()
# in sstate.bbclass); for do_image_oci that gate is False and the
# exclusion is skipped. extend_recipe_sysroot itself has a hardcoded
# "*-initial" skip but only for do_sdk_depends / do_populate_sdk_ext
# (staging.bbclass:457) -- an oe-core task allow-list we can't cleanly
# extend from a downstream layer.
#
# Filter *-initial do_populate_sysroot nodes out of BB_TASKDEPDATA before
# extend_recipe_sysroot walks it. extend_recipe_sysroot re-reads
# BB_TASKDEPDATA on each entry, so a setVar with the filtered dict is
# sufficient.
python oci_strip_initial_taskdepdata () {
    tdd =3D d.getVar("BB_TASKDEPDATA", False)
    if not tdd:
        return
    drop =3D {k for k, v in tdd.items()
            if v[1] =3D=3D "do_populate_sysroot" and v[0].endswith("-initial"=
)}
    if not drop:
        return
    filtered =3D {k: v for k, v in tdd.items() if k not in drop}
    for v in filtered.values():
        v[3].difference_update(drop)
    d.setVar("BB_TASKDEPDATA", filtered)
    bb.note("OCI: dropped %d *-initial node(s) to avoid libgcc collision" % l=
en(drop))
}
oci_strip_initial_taskdepdata[vardepsexclude] +=3D "BB_TASKDEPDATA"

python oci_attach_strip_prefunc () {
    task =3D "do_image_oci"
    if task in e.tasklist:
        deps =3D d.getVarFlag(task, "depends")
        if deps and "populate_sysroot" in deps:
            d.prependVarFlag(task, "prefuncs", "oci_strip_initial_taskdepdata=
 ")
}
oci_attach_strip_prefunc[eventmask] =3D "bb.event.RecipeTaskPreProcess"
addhandler oci_attach_strip_prefunc

Bruce