Yocto IMAGE_INSTALL vs RDEPENDS — Where Does the Package Go?

Yocto IMAGE_INSTALL vs RDEPENDS is the usual fork when someone asks “why is this package on the rootfs?” Short split: packages (or packagegroups) you mean to put on this image belong in IMAGE_INSTALL; packages another package must have at runtime belong in RDEPENDS. This is a minimal howto from the Yocto Project Customizing Images chapter and the Variables Glossary. No board anecdotes, no pricing, no affiliates.

When do you use IMAGE_INSTALL?

One-line answer: Names you intentionally include on the root filesystem go in image-side IMAGE_INSTALL. For local experiments use IMAGE_INSTALL:append in local.conf; for product images prefer a custom image recipe and/or packagegroups.

From the docs:

  • Prefer IMAGE_INSTALL:append = " pkg" in local.conf. The leading space matters; :append avoids ordering fights with ?= / image recipes better than +=.
  • Limit to one image with a pn override, e.g. IMAGE_INSTALL:append:pn-core-image-minimal = " strace".
  • For core-image-* only, CORE_IMAGE_EXTRA_INSTALL is an option.
  • For complex images, create an inherit packagegroup recipe and add that packagegroup package to IMAGE_INSTALL (Custom Package Groups).

Minimal local.conf example:

IMAGE_INSTALL:append = " strace"
# IMAGE_INSTALL:append:pn-core-image-minimal = " strace"

Custom image skeleton:

IMAGE_INSTALL = "packagegroup-core-boot my-app"
inherit core-image

IMAGE_INSTALL declares membership of this image. “App A always needs library B at runtime” is recipe RDEPENDS, not a flat image dump of every library.

When do you use RDEPENDS?

One-line answer: RDEPENDS:pkg is a hard runtime dependency on package names. If pkg is installed, its RDEPENDS targets are pulled in. Packagegroups list their contents the same way.

Glossary points:

  • Not the same as build-time DEPENDS (sysroot / headers / link). RDEPENDS is “must be on the target with this package.”
  • Always use a package override: RDEPENDS:${PN} = "libfoo".
  • In a packagegroup, each entry in PACKAGES gets RDEPENDS:${PN}-…; the image then only needs those packagegroup names in IMAGE_INSTALL.

Documented packagegroup pattern:

DESCRIPTION = "My Custom Package Groups"
inherit packagegroup

PACKAGES = "${PN}-apps ${PN}-tools"

RDEPENDS:${PN}-apps = "\
    dropbear \
    portmap \
    psplash \
"

RDEPENDS:${PN}-tools = "\
    oprofile \
    lttng-tools \
"

RRECOMMENDS:${PN}-tools = "kernel-module-oprofile"

Then on the image:

IMAGE_INSTALL:append = " packagegroup-custom-apps"

Optional pieces use RRECOMMENDS. BAD_RECOMMENDATIONS / NO_RECOMMENDATIONS can drop recommends; they do not override a hard RDEPENDS.

What goes wrong if you use both?

One-line answer: Listing the same package in IMAGE_INSTALL and in some package’s RDEPENDS usually still installs, but removal, exclusion, and audits break. Two paths now “own” why the package is on the image.

Common failure modes:

  1. Removed from IMAGE_INSTALL but still on the rootfs — another package’s (or packagegroup’s) RDEPENDS pulls it back.
  2. PACKAGE_EXCLUDE / BAD_RECOMMENDATIONS surprise — the glossary states recommends can be blocked; a hard RDEPENDS causes the build system to keep installing to avoid dependency errors.
  3. Scattered policy — the same name in image recipe, local.conf, app recipe, and packagegroup makes “why is it in the product image?” multi-path. That is why the manual pushes packagegroups: bundle with RDEPENDS, install the group via IMAGE_INSTALL.
  4. Role mix-up — stuffing libraries only into IMAGE_INSTALL while leaving app RDEPENDS empty means other images/SDK/package feeds miss the dependency. Duplicating an app’s RDEPENDS entries again in IMAGE_INSTALL is usually noise (unless you intentionally pin).

Practical split aligned with the manual:

GoalWhere
Must be on this image (app, tool, packagegroup)IMAGE_INSTALL (:append / image recipe)
Hard runtime need of a packageRDEPENDS:pkg
Shared product bundleinherit packagegroup + RDEPENDS → group name in IMAGE_INSTALL
Nice-to-haveRRECOMMENDS (optional BAD_RECOMMENDATIONS)

Reduce duplication:

  1. Put real runtime must-haves on the consumer recipe’s RDEPENDS.
  2. Bundle product sets in packagegroup RDEPENDS.
  3. Put app or packagegroup names (not every transitive library) on IMAGE_INSTALL.
  4. When removing, check who still holds an RDEPENDS edge (bitbake -e, buildhistory, package graphs)—not only the image list.

FAQ

Q. May I put libraries directly in IMAGE_INSTALL?
A. Yes, but if consumers omit RDEPENDS, other images or package installs can break. Prefer consumer RDEPENDS (or automatic shlib deps).

Q. Is a long IMAGE_INSTALL without packagegroups OK?
A. Fine for prototypes and local.conf. The manual calls packagegroups the best approach for complex custom images.

Q. Do I need both RDEPENDS and DEPENDS?
A. Different jobs: headers/link → DEPENDS; must co-exist on target → RDEPENDS. Auto runtime deps cover many shared libs; scripts/data/explicit package names still need RDEPENDS.

Takeaways

Image membership is IMAGE_INSTALL; hard runtime edges are RDEPENDS. Packagegroups bundle the latter and put only the group on the former—the mega-manual flow. Duplicating the same package on both rarely helps install and often hurts removal and audits. See Customizing Images and the Variables Glossary for IMAGE_INSTALL / RDEPENDS.

Official sources

  • Customizing Images
  • Variables Glossary (IMAGE_INSTALL, RDEPENDS, RRECOMMENDS, BAD_RECOMMENDATIONS, PACKAGE_EXCLUDE)
  • OE-Core example: meta/recipes-core/packagegroups/packagegroup-base.bb