[Yocto 시리즈 5] 첫 빌드 — core-image-minimal 만들고 QEMU로 부팅하기
by khd08012026. 7. 20.
반응형
4회차까지 해서 빌드 호스트 준비와 poky 클론을 마쳤어요. 이번 회차는 드디어 첫 빌드입니다. source oe-init-build-env 한 줄로 빌드 환경을 만들고, bitbake core-image-minimal로 부팅 가능한 리눅스 이미지를 통째로 빌드한 다음, 실제 보드 없이 QEMU 에뮬레이터로 부팅해서 로그인까지 해볼 거예요. 임베디드 리눅스를 배포판 단위로 빌드해 본 적이 없다면, 오늘이 가장 기억에 남는 회차가 될 겁니다.
poky를 클론했다고 해서 아무 셸에서나 bitbake를 칠 수 있는 게 아니에요. BitBake 실행 파일은 poky/bitbake/bin 아래에 있어서 기본 PATH에 잡혀 있지 않고, 빌드 설정과 산출물을 담을 빌드 디렉터리도 아직 없기 때문입니다. 이 두 가지를 한 번에 해결해 주는 것이 poky 최상위의 oe-init-build-env 스크립트예요. 실행하면 현재 셸의 PATH에 BitBake와 지원 스크립트 경로를 추가하고, 빌드 디렉터리를 만들어 그 안으로 이동시켜 줍니다.
여기서 실무적으로 중요한 포인트가 하나 있어요. 이 스크립트는 실행(./oe-init-build-env)이 아니라 반드시 source로 불러야 합니다. 환경 변수를 현재 셸에 심는 것이 목적이라, 자식 프로세스로 실행하면 아무 효과가 없거든요. 그리고 셸을 새로 열 때마다 다시 source 해야 해요. 팀에 새로 온 동료가 "어제는 됐는데 오늘은 bitbake: command not found가 나요"라고 하면, 십중팔구 새 터미널에서 이 단계를 빼먹은 겁니다.
1.2 실행해 보기 — 출력 메시지가 곧 로드맵
공식 Quick Build 문서의 명령 그대로 실행합니다.
cd poky
source oe-init-build-env
처음 실행하면 스크립트가 이런 취지의 안내를 출력해요. 공식 문서에 실린 메시지를 옮깁니다.
"You had no conf/local.conf file. This configuration file has therefore been created for you with some default values." … "You can now run 'bitbake <target>'" … "You can also run generated QEMU images with a command like 'runqemu qemux86-64'" — Yocto Project Quick Build (scarthgap)
이 안내문이 사실상 오늘 회차의 로드맵이에요. 기본 설정 파일(local.conf)이 자동으로 만들어졌고, 이제 bitbake <target>으로 빌드하면 되고, 빌드된 이미지는 runqemu로 부팅할 수 있다 — 이 세 문장이 1·2·3장의 순서 그대로입니다. 안내문에는 자주 쓰는 빌드 타깃 목록(core-image-minimal, core-image-full-cmdline, core-image-sato, core-image-weston 등)도 함께 출력되니, 처음 보는 분은 한 줄씩 읽어 보는 걸 권해요.
1.3 생성된 build/ 디렉터리 — local.conf와 bblayers.conf
스크립트가 끝나면 현재 위치가 poky/build로 바뀌어 있어요. 이 빌드 디렉터리가 앞으로 모든 빌드 작업의 근거지입니다. 갓 만들어진 시점에는 conf/ 아래 설정 파일 두 개가 핵심이에요.
conf/local.conf — 타깃 머신, 패키지 포맷, 다운로드 경로 등 로컬 사용자 설정 전부
conf/bblayers.conf — BitBake가 탐색할 레이어 목록
빌드를 한 번 돌리고 나면 이 디렉터리에 downloads/(받아 온 소스 아카이브), sstate-cache/(3회차에서 다룬 공유 상태 캐시), tmp/(모든 빌드 출력)가 자라나요. 각 디렉터리의 역할은 Reference Manual의 "The Build Directory"에 정리되어 있고, 그중 tmp/deploy/images/가 오늘 부팅에 쓸 최종 이미지가 놓이는 곳입니다.
빌드 전에 local.conf에서 확인할 것이 하나 있어요. 바로 타깃 머신을 정하는 MACHINE 변수입니다. Quick Build 문서는 기본 설정을 이렇게 설명해요.
즉 기본값은 실제 보드가 아니라 QEMU 에뮬레이션용 머신이에요. 참고로 문서 본문의 표현은 "qemux86 target"이지만 같은 문서의 부팅 단계는 qemux86-64를 사용하니, 여러분의 빌드가 어느 머신용인지는 생성된 local.conf의 MACHINE 줄에서 직접 확인하는 게 정확합니다(🧪 직접 해보기 2번). 이 시리즈는 문서의 부팅 예시와 동일한 qemux86-64 기준으로 진행할게요. local.conf의 나머지 항목들은 6회차에서 통째로 다룹니다.
2. 첫 빌드 — bitbake core-image-minimal
2.1 어떤 이미지부터 빌드할까
공식 Quick Build 문서는 예시로 core-image-sato를 빌드해요. Sato는 Yocto의 데모용 그래픽 데스크톱 환경이라 결과물이 화려하지만, 그만큼 빌드할 레시피 수가 많습니다. 첫 빌드라면 저는 core-image-minimal을 권해요. 부팅과 로그인이 되는 최소한의 이미지라 빌드 범위가 가장 작고, oe-init-build-env 안내문의 공통 타깃 목록에도 올라 있는 표준 타깃입니다. "가장 작은 성공"을 먼저 확보하고 나서 큰 이미지로 넓혀 가는 것이 디버깅 관점에서도 유리해요.
참고로 공통 타깃들의 성격을 한 줄씩 정리하면 이래요. core-image-minimal은 부팅 가능한 최소 이미지, core-image-full-cmdline은 콘솔 전용이지만 리눅스 명령 도구를 갖춘 이미지, core-image-sato는 Sato 그래픽 데스크톱 이미지, core-image-weston은 Wayland/Weston 기반 그래픽 이미지입니다. 어떤 걸 빌드하든 이후 절차는 동일해요.
2.2 빌드 시간을 줄이는 공식 처방 — sstate 미러와 hash equivalence
첫 빌드는 크로스 툴체인부터 커널까지 전부 소스에서 빌드하기 때문에 시간이 오래 걸려요. 소요 시간은 호스트 사양과 네트워크 속도에 따라 크게 달라지므로 수치를 단정하긴 어렵지만, "커피 한 잔"이 아니라 "다른 일을 하다 와야 하는" 단위라고 생각하는 게 안전합니다. 그래서 Quick Build 문서는 빌드 전에 local.conf에 아래 설정을 추가해 Yocto 프로젝트가 미리 빌드해 둔 sstate 캐시를 재사용하라고 권해요.
3회차에서 "sstate 캐시가 있으면 태스크를 실제로 실행하는 대신 결과물을 가져다 쓴다"고 정리했는데, 이 설정은 그 캐시 저장소를 내 디스크가 아니라 프로젝트 공식 서버(SSTATE_MIRRORS)까지 확장하는 거예요. BB_HASHSERVE·BB_SIGNATURE_HANDLER는 hash equivalence라는 메커니즘으로 "입력이 달라 보여도 결과가 같은 태스크"를 식별해 캐시 적중률을 높입니다(원리는 20회차 최적화 편에서 자세히 다룰게요). 외부 서버 접속이 필요한 설정이니, 폐쇄망 빌드 서버라면 이 단계는 건너뛰고 전체 빌드를 감수하면 됩니다.
2.3 빌드 실행 — 그리고 산출물은 어디에
이제 한 줄이면 됩니다.
bitbake core-image-minimal
실행하면 3회차에서 본 그림이 실제로 돌아가요. BitBake가 레시피 메타데이터를 파싱해 의존성 그래프를 만들고, 수천 개의 태스크(fetch → unpack → patch → configure → compile → install → package)를 병렬로 실행합니다. 화면에는 현재 실행 중인 태스크 수와 진행 상황이 계속 갱신되고, 에러 없이 끝나면 프롬프트로 돌아와요. 중간에 실패하더라도 당황할 것 없어요 — 이미 끝난 태스크는 sstate에 남아 있어서, 원인을 고치고 같은 명령을 다시 실행하면 실패 지점 근처부터 이어갑니다.
빌드가 끝난 이미지는 빌드 디렉터리의 tmp/deploy/images/<머신명>/ 아래에 놓여요. Reference Manual은 이 위치를 "빌드의 기본 출력물이 놓이는 곳"으로 설명하며, 커널 이미지·루트 파일시스템 등 타깃에 올릴 구성 요소들이 여기 모입니다. QEMU 머신 빌드라면 runqemu가 이 디렉터리를 알아서 뒤지기 때문에 경로를 외울 필요까지는 없지만, 실제 보드에 플래싱할 때는 이 경로에서 이미지를 꺼내게 되니 위치는 기억해 두세요.
3. QEMU로 부팅 — runqemu
3.1 runqemu — QEMU 옵션 지옥을 대신 감당하는 스크립트
QEMU를 직접 써 본 분은 알겠지만, 커널·디스크 이미지·네트워크 옵션을 손으로 다 지정하는 건 상당히 번거로워요. poky의 scripts/에 들어 있는 runqemu는 그 옵션 조합을 대신 처리해 주는 래퍼 스크립트입니다. 머신 이름만 주면 돼요.
runqemu qemux86-64
이미지를 명시하지 않으면 runqemu는 빌드 디렉터리의 deploy/images 아래에서 타임스탬프 기준으로 가장 최근에 빌드된 이미지를 찾아 부팅해요(출처: Development Tasks Manual, "Using the Quick EMUlator (QEMU)"). 방금 core-image-minimal을 빌드했다면 그게 올라옵니다. 여러 이미지를 빌드해 둔 상태라면 runqemu qemux86-64 core-image-minimal ext4처럼 이미지 이름과 파일 시스템 타입까지 명시해서 애매함을 없앨 수 있어요.
3.2 로그인과 종료
부팅이 끝나면 QEMU 창에 로그인 프롬프트가 떠요. 계정은 root, 비밀번호는 없습니다. 이게 되는 이유는 기본 생성된 local.conf의 EXTRA_IMAGE_FEATURES에 debug-tweaks가 들어 있기 때문이에요(여러분의 local.conf에서 직접 확인해 보세요). 공식 문서는 이 기능을 이렇게 정의합니다.
"Makes an image suitable for development (e.g. allows root logins, logins without passwords — including root ones, and enables post-installation logging)." — Reference Manual, "Image Features" (debug-tweaks)
정의에 "development"라고 못 박혀 있듯이, 이건 어디까지나 개발 편의 기능이에요. 제품 출하용 이미지에 debug-tweaks가 남아 있으면 비밀번호 없는 root 로그인이 그대로 열려 있는 셈이니, 릴리스 빌드 설정에서는 반드시 빠져 있어야 합니다. 로그인에 성공했다면 uname -a나 cat /etc/os-release로 방금 여러분이 빌드한 리눅스임을 확인해 보세요.
종료는 Quick Build 문서 그대로예요 — "Exit QEMU by either clicking on the shutdown icon or by typing Ctrl-C in the QEMU transcript window from which you evoked QEMU"(셧다운 아이콘을 클릭하거나, QEMU를 실행한 터미널에서 Ctrl-C).
3.3 알아 두면 좋은 옵션 — nographic, kvm
원격 SSH로 빌드 서버에 붙어 작업한다면 그래픽 창을 띄울 수 없죠. 이럴 때는 runqemu qemux86-64 nographic처럼 nographic 옵션을 붙이면 그래픽 콘솔 없이 현재 터미널을 시리얼 콘솔로 써서 부팅합니다. 콘솔 전용인 core-image-minimal과의 궁합도 좋아요.
부팅 속도가 답답하다면 kvm 옵션을 검토하세요. 호스트 CPU의 가상화 지원을 이용하는 KVM 가속을 켜는 옵션인데, 머신이 qemux86·qemux86-64일 것, 그리고 호스트의 /dev/kvm에 읽기/쓰기 권한이 있을 것이 조건입니다(출처: 위 QEMU 문서). 이 밖에 root 권한 없이 네트워킹을 쓰는 slirp, QEMU 옵션을 직접 끼워 넣는 qemuparams="..." 같은 옵션도 있으니, 필요해질 때 문서의 옵션 표를 찾아보면 됩니다.
4. 6.0의 새 방식 — bitbake-setup 미리 보기
4.1 무엇이 달라지나
4회차 끝에서 예고했던 내용이에요. 최신 개발판(6.0-tip) 문서의 Quick Build는 poky를 수동으로 클론하는 대신 bitbake-setup이라는 새 도구로 환경을 구성하는 방식으로 전면 개편됐습니다. bitbake 저장소 하나만 받으면, bitbake-setup init이 필요한 레이어들을 알아서 받아 오고 대화형으로 배포판·머신 설정까지 잡아 줘요. 완료되면 빌드 디렉터리(build/), 레이어 모음(layers/), 설정(config/)이 분리된 구조가 만들어집니다.
설정 방식도 달라져요. local.conf를 손으로 편집하는 대신, configuration fragment라는 설정 조각을 bitbake-config-build 명령으로 켜고 끄는 모듈식 구성이 중심이 됩니다. 상징적인 예가 로그인이에요 — scarthgap에서는 debug-tweaks가 기본 local.conf에 들어 있어 비밀번호 없는 root 로그인이 암묵적으로 열리지만, 6.0 문서에서는 core/yocto/root-login-with-empty-password라는 fragment를 명시적으로 켜는 것으로 바뀌었습니다. 개발 편의 기능을 "기본 제공"에서 "의식적 선택"으로 옮긴 셈이라, 방향성이 보이는 변화예요.
4.2 명령 흐름 훑어보기
6.0-tip Quick Build 문서의 흐름을 요약하면 이렇습니다(전체는 참고 링크의 문서 참조).
git clone https://git.openembedded.org/bitbake
./bitbake/bin/bitbake-setup init
# 대화형 선택 대신 한 줄로:
# ./bitbake/bin/bitbake-setup init --non-interactive poky-master poky distro/poky machine/qemux86-64
source poky-master/build/init-build-env
bitbake-config-build list-fragments
bitbake core-image-sato
runqemu snapshot
oe-init-build-env 자리에 init-build-env가, local.conf 편집 자리에 fragment 조작이 들어온 것만 대응시켜 보면 오늘 배운 구조가 그대로 비쳐요. 큰 그림 — "환경을 잡고, 설정을 확인하고, bitbake로 빌드해서, runqemu로 부팅한다" — 은 달라지지 않았습니다.
ℹ️ 버전 참고 — 이 시리즈의 기준인 LTS(scarthgap)에서는 여전히 1~3장의 oe-init-build-env 방식이 정식 절차이고, 6.0에서도 기존 수동 방식은 계속 지원돼요. 지금은 "이런 방향으로 바뀌고 있다"만 알아 두면 충분하고, 실습은 scarthgap 흐름으로 진행하면 됩니다.
📌 실무 팁 — 첫 빌드처럼 오래 걸리는 빌드는 tmux나 screen 같은 터미널 멀티플렉서 안에서 실행하는 습관을 권해요. SSH 세션이 끊기는 순간 몇 시간짜리 빌드가 함께 죽는 사고를 막아 줍니다. 그리고 빌드가 끝난 직후 같은 bitbake core-image-minimal을 한 번 더 실행해 보세요 — 모든 태스크가 sstate 캐시에 적중해 순식간에 끝나는 걸 보면, 3회차에서 글로 읽은 "실행하지 않고 재사용한다"가 몸으로 이해될 거예요.
빌드 환경 초기화: cd poky; source oe-init-build-env — 안내 메시지가 출력되고 현재 디렉터리가 build로 바뀌는지, conf/local.conf가 생겼는지 확인하세요.
타깃 머신 확인: grep "^MACHINE" conf/local.conf — 주석이 아닌 MACHINE 줄의 값을 확인합니다. 이 값이 뒤에서 runqemu에 줄 머신 이름이에요.
(선택) 빌드 가속: 2.2절의 sstate 미러·hash equivalence 4줄을 conf/local.conf 끝에 추가 — 외부망이 되는 환경에서만.
첫 빌드: bitbake core-image-minimal — 완료까지 상당히 걸립니다. 끝나면 ls tmp/deploy/images/*/로 커널·루트파일시스템 이미지 파일들이 생겼는지 확인하세요.
QEMU 부팅: runqemu qemux86-64 (2번에서 확인한 머신 이름 사용, 원격 셸이면 nographic 추가) — 로그인 프롬프트에서 root 입력, uname -a로 부팅 확인 후 QEMU를 실행한 터미널에서 poweroff 명로 종료합니다.
✍️ 내 실행 결과 1. 빌드 환경 초기화
2. 타깃 머신 확인
3. 빌드 가속 4. 첫 빌드 5. QEMU 부팅
6. QEMU 종료
마무리
이번 회차로 시리즈의 첫 번째 큰 이정표를 넘었어요. source oe-init-build-env로 빌드 환경과 build/ 디렉터리를 만들고, bitbake core-image-minimal로 부팅 가능한 리눅스 이미지를 소스에서 통째로 빌드했으며, runqemu로 부팅해서 root 로그인까지 확인했습니다. sstate 미러로 첫 빌드 시간을 줄이는 공식 처방과, 6.0에서 bitbake-setup·configuration fragment로 워크플로우가 재편되는 방향도 미리 봤어요.
1~5회차를 관통하는 그림을 요약하면 이래요. Yocto는 배포판을 빌드하는 시스템이고(1회차), 그 재료는 레이어에 담긴 레시피이며(2회차), BitBake가 태스크 파이프라인과 sstate 캐시로 그것을 빌드하고(3회차), 준비된 호스트에서(4회차) 오늘 그 전체를 실제로 돌려 부팅까지 확인했습니다. 이제부터는 이 동작하는 시스템을 "내 것으로 바꾸는" 단계로 넘어가요.
다음 6회차에서는 오늘 자동 생성된 local.conf와 bblayers.conf를 한 줄씩 뜯어봅니다. MACHINE, DL_DIR, SSTATE_DIR, BB_NUMBER_THREADS, PARALLEL_MAKE — 빌드 속도와 디스크 사용량을 좌우하는 설정들을 실무 기준으로 정리할게요.
댓글