Yocto로 이미지를 만들다 보면 패키지 하나를 넣거나 빼야 할 일이 계속 생긴다. 그런데 local.conf에 IMAGE_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.bb가 IMAGE_INSTALL = "packagegroup-core-boot ${CORE_IMAGE_EXTRA_INSTALL}"로 재할당하기 때문이다. 설정 파일 단계에서 +=로 더한 값은 이 할당에 덮여 사라진다. :append는 파싱이 끝난 뒤 적용되므로 살아남는다.
| 방법 | 적어야 할 위치 | 적용 범위 |
|---|---|---|
IMAGE_INSTALL:append = " pkg" | local.conf | 빌드하는 모든 이미지 |
CORE_IMAGE_EXTRA_INSTALL += "pkg" | local.conf | core-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:remove | IMAGE_INSTALL에 직접 적힌 항목 | 목록에서 제거 |
BAD_RECOMMENDATIONS | RRECOMMENDS로 끌려온 패키지 | 설치하지 않음 |
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:append나 CORE_IMAGE_EXTRA_INSTALL, 이미지 레시피 안에서는 IMAGE_INSTALL +=를 쓴다. 제외는 대상이 IMAGE_INSTALL에 직접 적힌 항목인지, RRECOMMENDS로 딸려온 것인지, 필수 RDEPENDS인지에 따라 IMAGE_INSTALL:remove·BAD_RECOMMENDATIONS·PACKAGE_EXCLUDE로 갈린다. 어느 쪽이든 빌드를 돌리기 전에 bitbake -e로 변수 값을 확인하고, 빌드 후에는 매니페스트 diff로 결과를 한 번 더 확인하는 흐름이 가장 빠르다. 변경 후 재빌드는 rootfs 관련 태스크만 다시 도니 1~5분이면 끝난다.