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

Koen Kooi <[email protected]> Wed, 29 Jul 2026 14:03:24 +0200
Newsgroups org.yoctoproject.lists.meta-virtualization
Message-ID <[email protected]>

> Op 29 jul 2026, om 05:17 heeft Bruce Ashfield via =
lists.yoctoproject.org <[email protected]>=
 het volgende geschreven:
>=20
> [...]
>=20
> Two questions to unblock:
>=20
> 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.

The incredibly messy WIP branch is here: =
https://github.com/koenkooi/meta-ai/tree/full-integration-test, you can =
build it via kas-container, but that will apply these (and more) patches =
to meta-virtualization automatically.

The important bits:

 meta-ai-tensorflow-lite-oci
   OCI_LAYER_MODE =3D "multi"
   OCI_LAYERS =3D "tensorflow-lite:packages:tensorflow-lite"
   OCI_BASE_IMAGE =3D "meta-ai-container-base-oci"

 meta-ai-container-base-oci
   OCI_LAYERS =3D =
"base:packages:base-files+base-passwd+netbase+glibc+libgcc+<abseil =
libs>"

DEPENDS in app image: flatbuffers-tflite, jpeg, libeigen, protobuf, plus =
gcc-runtime/abseil pulled through the base layer.

> 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 reproduced it with qemuarm64 as well now, instead of meta-qcom =
machines:

MACHINE=3Dqemuarm64
  * meta-virtualization master-next
  * IMAGE_PKGTYPE unset -> default ipk/opkg
  * No PACKAGECONFIG

The reproducer itself, clean sstate, first try, unpatched:

 ERROR: meta-ai-tensorflow-lite-oci-1.0-r0 do_image_oci: The file =
/usr/lib/aarch64-oe-linux/16.1.0/crtendS.o is installed by both libgcc =
and libgcc-initial, aborting

Now the bad news: the patch fixes do_image_oci, but not =
do_image_complete, that hits the same issue on the same file:

 ERROR: meta-ai-tensorflow-lite-oci-1.0-r0 do_image_complete: Error =
executing a python function in exec_func_python() autogenerated:
 Exception: FileExistsError: [Errno 17] File exists: =
'/build/oe/repro/bugtest-qemux86/build/tmp/sysroots-components/cortexa57/l=
ibgcc-initial/usr/lib/aarch64-oe-linux/16.1.0/crtendS.o' -> =
'/build/oe/repro/bugtest-qemux86/build/tmp/work/qemuarm64-oe-linux/meta-ai=
-tensorflow-lite-oci/1.0/recipe-sysroot/usr/lib/aarch64-oe-linux/16.1.0/cr=
tendS.o'

So patch 2/2 isn't enough to fix this issue :(

regards,

Koen

>=20
> 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.
>=20
> 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.
>=20
> 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.
>=20
> # =
=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" % len(drop))
> }
> oci_strip_initial_taskdepdata[vardepsexclude] +=3D "BB_TASKDEPDATA"
>=20
> 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
>=20
> Bruce
>=20
> -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-
> Links: You receive all messages sent to this group.
> View/Reply Online (#10014): =
https://lists.yoctoproject.org/g/meta-virtualization/message/10014
> Mute This Topic: https://lists.yoctoproject.org/mt/120482434/9418801
> Group Owner: [email protected]
> Unsubscribe: =
https://lists.yoctoproject.org/g/meta-virtualization/unsub =
[[email protected]]
> -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-
>=20