Yocto 빌드에서 특정 패키지를 포함/제외하는 방법

Yocto로 이미지를 만들다 보면 패키지 하나를 넣거나 빼야 할 일이 계속 생긴다. 그런데 local.confIMAGE_INSTALL += "strace"라고 적어도 이미지에 strace가 들어가지 않는다. 이미지 레시피가 IMAGE_INSTALL을 다시 할당해버리기 때문인데, 이처럼 변수마다 적용 시점과 범위가 달라서 문서를 봐도 어느 것을 써야 할지 헷갈린다. 이 글에서는 poky scarthgap(5.0.19)에서 패키지를 포함·제외하는 변수들이 실제로 어떻게 동작하는지 bitbake -e로 확인하고, 이미지 매니페스트로 결과를 검증한다.

실습 환경

$ git clone --branch scarthgap --depth 1 https://git.yoctoproject.org/poky
$ cd poky && grep DISTRO_VERSION meta-poky/conf/distro/poky.conf
DISTRO_VERSION = "5.0.19"

$ bitbake/bin/bitbake --version
BitBake Build Tool Core version 2.8.1

$ source oe-init-build-env build
$ grep ^MACHINE conf/local.conf
MACHINE ??= "qemux86-64"

대상 이미지는 core-image-minimal, 머신은 기본값인 qemux86-64다. 아래 변수 동작은 walnascar나 master에서도 같다.

기본 이미지에 무엇이 들어가는지 확인

빌드하기 전에 bitbake -e로 최종 확정된 변수 값을 볼 수 있다. 파싱만 하므로 30초면 끝난다.

$ bitbake -e core-image-minimal | grep -E '^(IMAGE_INSTALL|CORE_IMAGE_EXTRA_INSTALL|IMAGE_FEATURES|EXTRA_IMAGE_FEATURES|PACKAGE_EXCLUDE|BAD_RECOMMENDATIONS|NO_RECOMMENDATIONS)='
BAD_RECOMMENDATIONS=""
CORE_IMAGE_EXTRA_INSTALL=""
EXTRA_IMAGE_FEATURES="debug-tweaks"
IMAGE_FEATURES="debug-tweaks"
IMAGE_INSTALL="packagegroup-core-boot "
NO_RECOMMENDATIONS=""
PACKAGE_EXCLUDE=""

IMAGE_INSTALL에는 패키지그룹 하나뿐이다. 실제 패키지는 그 패키지그룹의 RDEPENDS/RRECOMMENDS로 끌려 들어온다.

$ bitbake -e packagegroup-core-boot | grep -E '^R(DEPENDS|RECOMMENDS):packagegroup-core-boot='
RDEPENDS:packagegroup-core-boot="base-files base-passwd busybox busybox-hwclock
  modutils-initscripts initscripts netbase busybox sysvinit udev
  update-alternatives-opkg v86d"
RRECOMMENDS:packagegroup-core-boot="busybox-syslog init-ifupdown"

RDEPENDS는 반드시 설치되고 RRECOMMENDS는 “있으면 설치”라 빼는 방법이 서로 다르다. 제외 절에서 이 차이가 그대로 드러난다.

패키지 추가하기

local.conf에 네 가지 방식으로 strace를 넣어보고 bitbake -e로 결과를 비교했다.

### local.conf: IMAGE_INSTALL += "strace"
IMAGE_INSTALL="packagegroup-core-boot "              <-- 반영 안 됨

### local.conf: IMAGE_INSTALL:append = " strace"
IMAGE_INSTALL="packagegroup-core-boot  strace"

### local.conf: CORE_IMAGE_EXTRA_INSTALL += "strace"
IMAGE_INSTALL="packagegroup-core-boot  strace"

### local.conf: EXTRA_IMAGE_FEATURES += "tools-debug"
IMAGE_INSTALL="packagegroup-core-boot "
IMAGE_FEATURES="debug-tweaks tools-debug"

첫 번째가 반영되지 않는 이유는 core-image-minimal.bbIMAGE_INSTALL = "packagegroup-core-boot ${CORE_IMAGE_EXTRA_INSTALL}"재할당하기 때문이다. 설정 파일 단계에서 +=로 더한 값은 이 할당에 덮여 사라진다. :append는 파싱이 끝난 뒤 적용되므로 살아남는다.

방법적어야 할 위치적용 범위
IMAGE_INSTALL:append = " pkg"local.conf빌드하는 모든 이미지
CORE_IMAGE_EXTRA_INSTALL += "pkg"local.confcore-image 계열 이미지
IMAGE_INSTALL += "pkg"커스텀 이미지 레시피(.bb)해당 이미지만
EXTRA_IMAGE_FEATURES += "feature"local.conf기능 묶음 단위

맨 앞 공백을 빼먹으면(IMAGE_INSTALL:append = "strace") 앞 항목과 붙어 ...bootstrace가 되므로 :append에는 항상 선행 공백을 넣는다. 기능 묶음이 실제로 무엇을 넣는지는 해당 패키지그룹을 조회하면 된다.

$ bitbake -e packagegroup-core-tools-debug | grep '^RDEPENDS:packagegroup-core-tools-debug='
RDEPENDS:packagegroup-core-tools-debug="gdb gdbserver libc-mtrace strace"

변수만 확인하고 끝내지 말고 이미지를 다시 만들어 매니페스트로 확인한다. IMAGE_INSTALL:append = " strace"를 넣고 재빌드한 결과다.

$ bitbake core-image-minimal
NOTE: Tasks Summary: Attempted 4110 tasks of which 4079 didn't need to be rerun and all succeeded.

real    5m15.428s

$ diff manifest_base.txt tmp/deploy/images/qemux86-64/core-image-minimal-qemux86-64.rootfs.manifest
28a29
> strace core2_64 6.7

전체 빌드는 4090개 태스크에 6시간 50분이 걸렸지만, 패키지 하나를 더하는 재빌드는 31개 태스크만 다시 돌아 5분에 끝난다.

패키지 제외하기

IMAGE_INSTALL:remove부터 확인해 본다. 네 가지 경우를 bitbake -e로 비교했다.

### IMAGE_INSTALL:append = " strace gdb" + IMAGE_INSTALL:remove = "gdb"
IMAGE_INSTALL="packagegroup-core-boot  strace "

### 순서를 바꿔 remove를 먼저 적어도 결과는 같다
IMAGE_INSTALL="packagegroup-core-boot  strace "

### IMAGE_INSTALL:remove = "packagegroup-core-boot"
IMAGE_INSTALL=" "

### IMAGE_INSTALL:remove = "busybox"
IMAGE_INSTALL="packagegroup-core-boot "         <-- 아무 변화 없음

:remove는 쓴 순서와 관계없이 항상 마지막에 적용되고, IMAGE_INSTALL에 적힌 항목만 지운다. busybox처럼 패키지그룹이 RDEPENDS로 끌고 오는 패키지는 목록에 없으니 지워지지 않는다. 이런 경우에는 아래 수단을 쓴다.

변수대상동작
IMAGE_INSTALL:removeIMAGE_INSTALL에 직접 적힌 항목목록에서 제거
BAD_RECOMMENDATIONSRRECOMMENDS로 끌려온 패키지설치하지 않음
NO_RECOMMENDATIONS = "1"모든 RRECOMMENDS일괄 무시
PACKAGE_EXCLUDE모든 패키지강제 제외, 필수 의존이면 rootfs 실패

RRECOMMENDS로 들어온 패키지 빼기

기본 이미지에는 packagegroup-core-boot가 권장하는 busybox-syslog가 들어 있다. BAD_RECOMMENDATIONS에 적고 재빌드하면 매니페스트에서 사라진다.

BAD_RECOMMENDATIONS = "busybox-syslog"
$ bitbake core-image-minimal
NOTE: Tasks Summary: Attempted 4090 tasks of which 4080 didn't need to be rerun and all succeeded.

real    1m3.346s

$ diff manifest_base.txt tmp/deploy/images/qemux86-64/core-image-minimal-qemux86-64.rootfs.manifest
5d4
< busybox-syslog core2_64 1.36.1

권장 패키지를 전부 무시하려면 NO_RECOMMENDATIONS = "1"을 쓰면 되지만, 이미지 전체에 영향을 주므로 필요한 것까지 빠질 수 있다.

RDEPENDS로 들어온 패키지를 빼려고 하면

PACKAGE_EXCLUDE는 설치 자체를 막는 변수라 필수 의존 패키지에 걸면 rootfs 생성이 실패한다. busybox를 제외해봤다.

$ bitbake core-image-minimal
ERROR: core-image-minimal-1.0-r0 do_rootfs: Could not invoke dnf. Command '... -x busybox
  --nogpgcheck install packagegroup-core-boot run-postinsts' returned 1
ERROR: Task (.../core-image-minimal.bb:do_rootfs) failed with exit code '1'

$ grep -i problem tmp/work/qemux86_64-poky-linux/core-image-minimal/1.0/temp/log.do_rootfs
 Problem: package packagegroup-core-boot-1.0-r0.qemux86_64 from oe-repo requires busybox,
   but none of the providers can be installed

실패 원인은 bitbake 출력이 아니라 log.do_rootfs에 남는다. 이렇게 필수 의존으로 걸린 패키지는 강제로 빼는 대신 그것을 요구하는 패키지그룹을 커스텀 패키지그룹으로 교체하거나, DISTRO_FEATURES에서 해당 기능을 빼는 쪽이 맞다.

무엇이 왜 들어갔는지 추적

의도치 않은 패키지가 보이면 bitbake -g로 의존 그래프를 뽑고 oe-depends-dot으로 경로를 역추적한다.

$ bitbake -g core-image-minimal
NOTE: PN build list saved to 'pn-buildlist'
NOTE: Task dependencies saved to 'task-depends.dot'

$ ../scripts/oe-depends-dot -k busybox -w task-depends.dot
Because: core-image-minimal packagegroup-core-boot
core-image-minimal -> packagegroup-core-boot -> busybox

단 이 그래프는 레시피(PN) 단위라 busybox-syslog 같은 패키지 이름으로는 찾을 수 없다. 패키지 이름은 빌드 후 oe-pkgdata-util로 조회한다.

$ oe-pkgdata-util lookup-recipe busybox-syslog
busybox

$ oe-pkgdata-util list-pkgs -p busybox
busybox
busybox-dbg
busybox-dev
busybox-hwclock
busybox-ptest
busybox-src
busybox-syslog
busybox-udhcpc

$ oe-pkgdata-util find-path /bin/busybox
busybox: /bin/busybox

이미지에 최종적으로 설치된 패키지 목록은 배포 디렉터리의 매니페스트에 남는다. core-image-minimal은 35개뿐이라 눈으로 훑어도 된다.

$ head -12 tmp/deploy/images/qemux86-64/core-image-minimal-qemux86-64.rootfs.manifest
base-files qemux86_64 3.0.14
base-passwd core2_64 3.6.8
busybox core2_64 1.36.1
busybox-hwclock core2_64 1.36.1
busybox-syslog core2_64 1.36.1
busybox-udhcpc core2_64 1.36.1
eudev core2_64 3.2.14
init-ifupdown qemux86_64 1.0
init-system-helpers-service core2_64 1.66
initscripts core2_64 1.0
initscripts-functions core2_64 1.0
kernel-6.6.144-yocto-standard qemux86_64 6.6.144+git0+a77e1b9654_2baf8e92ef

주의사항

  • IMAGE_INSTALL에 적는 것은 레시피(PN) 이름이 아니라 패키지 이름이다. busybox 레시피는 busybox, busybox-syslog, busybox-udhcpc 등 여러 패키지를 만든다.
  • local.conf에서는 IMAGE_INSTALL +=가 동작하지 않는다. :append(선행 공백 포함) 또는 CORE_IMAGE_EXTRA_INSTALL을 쓴다.
  • PACKAGE_EXCLUDE는 의존성을 무시하는 것이 아니라 설치를 막는 것이다. 다른 패키지가 RDEPENDS로 요구하면 rootfs 생성이 실패한다.
  • Ubuntu 24.04를 빌드 호스트로 쓰면 AppArmor의 unprivileged user namespace 제한 때문에 bitbake가 시작하자마자 User namespaces are not usable by BitBake 오류로 멈춘다. sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0으로 풀 수 있다.

마무리

정리하면 추가는 local.conf에서 IMAGE_INSTALL:appendCORE_IMAGE_EXTRA_INSTALL, 이미지 레시피 안에서는 IMAGE_INSTALL +=를 쓴다. 제외는 대상이 IMAGE_INSTALL에 직접 적힌 항목인지, RRECOMMENDS로 딸려온 것인지, 필수 RDEPENDS인지에 따라 IMAGE_INSTALL:remove·BAD_RECOMMENDATIONS·PACKAGE_EXCLUDE로 갈린다. 어느 쪽이든 빌드를 돌리기 전에 bitbake -e로 변수 값을 확인하고, 빌드 후에는 매니페스트 diff로 결과를 한 번 더 확인하는 흐름이 가장 빠르다. 변경 후 재빌드는 rootfs 관련 태스크만 다시 도니 1~5분이면 끝난다.

참고

답글 남기기