임베디드 시스템 빌더, Yocto [2]

나우히즈·2025년 10월 18일

1편에 이어 이제 본격적으로 Yocto에 대해 알아보자.

Yocto Project

Yocto Project는 임베디드 리눅스 시스템을 자동으로 빌드하는 통합 빌드 프레임워크.
하나의 명령으로,

  • 툴체인 (크로스 컴파일러)
  • 부트로더 (U-Boot 등)
  • 커널
  • 루트파일시스템 (BusyBox, 라이브러리, 드라이버 등 포함)

를 모두 빌드함.

이 모든 걸 수작업으로 구성하면 매우 복잡하기 때문에, Yocto라는 자동화된 빌드 파이프라인을 이용하게 됨.


Yocto 빌드 구조

  • Yocto의 빌드는 “레시피(Recipe)” 중심.
  • 레시피는 특정 컴포넌트를 어떻게 빌드할지를 기술한 메타데이터 파일(.bb).

예를 들어:

busybox_1.36.1.bb

이런 파일은 BusyBox를 다운로드하고, 패치 적용하고, 빌드해서 rootfs에 넣는 과정을 정의합니다.

  • 파이썬 + 셸 스크립트 기반으로 작성되어 있음
  • 여러 개의 레시피를 그룹으로 묶어 “이미지(image)”를 구성

BitBake — 빌드 엔진이자 스케줄러

BitBake는 Yocto의 핵심 빌드 엔진.
bitbake <image> 명령을 입력하면 BitBake가 다음을 자동으로 수행

  1. 모든 .bb 레시피를 읽음
  2. 의존 관계를 파악하고,
  3. 각 작업(Task)을 올바른 순서로 실행
  4. 필요한 소스 다운로드, 패치, 컴파일, 패키징 수행

즉, BitBake는 “Makefile + 빌드 스케줄러 + 패키지 관리자”의 역할을 동시에 수행


주요 구성요소 상세 설명

구성요소수행 내용
OE-Core Yocto의 기반 메타데이터 세트. OpenEmbedded와 공유되며, 빌드 규칙·클래스·함수 등 핵심 로직을 제공
BitBake실제 빌드 스케줄러로, 모든 레시피(.bb)를 읽고 Task 단위로 실행
PokyYocto의 기본 “레퍼런스 배포판”. OE-Core, BitBake, 메타데이터 등을 패키징한 통합 세트
Documentation공식 문서 및 개발 가이드라인. 각 컴포넌트의 작성 규칙과 베스트 프랙티스 제공
ToasterBitBake 빌드를 시각적으로 관리할 수 있는 웹 기반 GUI 도구. 빌드 로그, 레시피, 패키지 상태를 브라우저에서 관리 가능

빌드 동작 개념

Yocto의 전체 빌드 흐름은 다음과 같이 이어집니다 👇

레시피(.bb) / 메타데이터(.bbclass, .conf)
       ↓
BitBake 엔진이 파싱 및 의존성 분석
       ↓
태스크 스케줄링 (fetch → patch → compile → package → rootfs)
       ↓
OE-Core의 규칙에 따라 각 Task 실행
       ↓
Poky (레퍼런스 구성) 기준으로 최종 이미지 생성

결과적으로 tmp/deploy/images/<machine>/ 아래에
커널, 부트로더, 루트파일시스템, SD카드 이미지(.wic 등)가 생성됩니다.


OE-Core

OE-Core(OpenEmbedded Core) 는 Yocto 프로젝트가 사용하는 “핵심 빌드 규칙, 클래스, 함수, 레시피”가 모여 있는 기본 메타데이터 계층(Base Metadata Layer).

즉, OE-Core는

  • BitBake가 실제로 읽어들일 빌드 규칙,
  • 각 패키지(커널, BusyBox, bash 등)를 빌드하는 방법,
  • 이미지를 구성하는 정책(루트FS, 패키지 형식 등)

을 정의하는 라이브러리 역할을 함.


OE-Core 구성

OE-Core는 poky 내부 meta/ 디렉터리에 존재.

poky/
 ├── bitbake/          ← BitBake 빌드 엔진
 ├── meta/             ← OE-Core (OpenEmbedded Core)
 ├── meta-poky/
 ├── meta-skeleton/
 └── meta-yocto-bsp/

이 meta/ 디렉터리 안에는 아래와 같은 폴더들이 들어 있어요 👇

폴더설명
classes/.bbclass 파일 — 빌드 공통 규칙 (예: autotools, kernel, image 등)
conf/전역 설정 (distro, machine, bitbake.conf 등)
recipes-*각 패키지별 레시피 (recipes-core, recipes-devtools, recipes-kernel, recipes-graphics 등)
files/패치, 설정 스크립트, 추가 자료

OE-Core 역할

역할설명
① 공통 빌드 클래스 제공classes/*.bbclass 파일에 빌드 로직 정의. 예: autotools.bbclass, kernel.bbclass
② 기본 패키지 레시피 제공busybox, bash, udev, glibc, opkg 같은 필수 레시피 포함
③ 전역 설정 제공타깃 CPU, 크로스 컴파일 옵션, 루트FS 포맷, 이미지 정책 등
④ 태스크 체계 정의fetch → unpack → patch → compile → install → package → image 의 빌드 단계(Task) 정의

즉, BitBake가 실제로 무엇을 빌드하고 어떤 순서로 실행할지를 정의하는 규칙 이 OE-Core.

BitBake 가 OE-Core를 참조하는 과정

예를 들어 busybox를 빌드한다고 하면:

  1. BitBake가 meta/recipes-core/busybox/busybox_1.36.1.bb 레시피를 읽음
  2. busybox.bbclass의 빌드 규칙을 적용 (do_compile, do_install 등)
  3. OE-Core의 설정(bitbake.conf, distro.conf)을 참조하여 빌드 경로, 크로스컴파일러 설정
  4. 빌드 결과를 rootfs에 패키징

이 전 과정이 OE-Core에 정의된 규칙에 따라 수행.

좋아요 👍
이제 Yocto의 “레이어(layer)” 개념과 bitbake-layers 명령어의 역할을 짚고 넘어가면
Yocto의 구조를 완전히 이해했다고 봐도 될 정도예요.


bitbake-Layers

레이어(Layer) 는 Yocto의 “빌드 구성 요소를 논리적으로 나눈 단위(모듈)”

쉽게 말해 각 기능이나 보드, 배포판, 패키지 그룹을 독립적으로 관리하기 위한 폴더 단위.

Yocto 빌드 시스템은 모든 걸 “메타데이터(metadata)”로 구성.

이 메타데이터는 레시피(.bb), 클래스(.bbclass), 설정파일(.conf) 들로 이뤄져 있는데, 이걸 역할별로 묶은 그룹 단위가 바로 “레이어”


실제 예시

Poky 안에는 이미 여러 개의 레이어가 존재.

poky/
├── bitbake/
├── meta/             ← OE-Core (기본 룰)
├── meta-poky/        ← poky 배포판 정책
├── meta-yocto-bsp/   ← 예제 보드(BSP) 지원
└── meta-skeleton/    ← 예시 템플릿

그리고 실제로 bblayers.conf에는 이런 식으로 등록됩니다 👇

BBLAYERS ?= " \
  /home/user/yocto/poky/meta \
  /home/user/yocto/poky/meta-poky \
  /home/user/yocto/poky/meta-yocto-bsp \
  /home/user/yocto/meta-myproject \
"

즉, BitBake는 이 “레이어 목록”을 기준으로 빌드할 때 사용할 메타데이터를 찾음.


레이어의 역할 구조

레이어 종류역할예시
Core Layer (meta)기본 빌드 규칙과 표준 패키지 제공meta (OE-Core)
Distro Layer배포판 정책 정의meta-poky
BSP Layer하드웨어 보드별 설정meta-yocto-bsp, meta-raspberrypi, meta-ti
Software Layer특정 소프트웨어 패키지 묶음meta-openembedded, meta-qt5, meta-python
Custom Layer사용자가 만든 레시피나 설정meta-myproject

이렇게 역할별로 나누면, 필요한 기능만 조합해서 효율적으로 빌드할 수 있음.


bitbake-layers 명령어

명령설명예시
bitbake-layers show-layers현재 등록된 레이어 목록 출력meta, meta-poky, meta-yocto-bsp 등
bitbake-layers add-layer <path>새로운 레이어 추가 (bblayers.conf에 등록됨)bitbake-layers add-layer ../meta-myproject
bitbake-layers remove-layer <path>레이어 제거bitbake-layers remove-layer ../meta-qt5
bitbake-layers show-recipes현재 인식 중인 모든 레시피 목록 표시
bitbake-layers flatten모든 레이어 메타데이터를 병합한 단일 디렉터리 생성 (디버깅용)

즉,

  • 어떤 레이어들이 현재 빌드에 포함되어 있는지 확인하고,
  • 새 레이어를 추가하거나 제거할 수 있게 해주는 도구예요.

실전 : LED Layer를 포키에 추가

➡️ 커널 모듈(.ko)이나 사용자 공간 프로그램을 하나의 레시피(recipe) 로 정의
➡️ 그 레시피를 새 레이어(meta-led) 에 넣음
➡️ bblayers.conf에 등록

이 과정을 거치면 BitBake는 bitbake core-image-minimal 시, LED 드라이버를 자동으로 빌드해서 rootfs에 포함함.


새 레이어 생성

먼저 Poky 빌드 환경을 초기화하고:

source poky/oe-init-build-env

그 다음 레이어 생성:

bitbake-layers create-layer ../meta-led

→ 결과 구조:

meta-led/
 ├── conf/
 │   └── layer.conf
 ├── recipes-example/
 │   └── example/
 │       └── example_0.1.bb
 └── COPYING.MIT

LED 드라이버 레시피 작성

(1) 예시 구조

meta-led/
 └── recipes-kernel/
     └── led-driver/
         ├── led-driver.c
         └── led-driver.bb

(2) 예시 코드 (간단한 커널 모듈)

led-driver.c

#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/init.h>

#define LED_GPIO 18  // 예: GPIO 18번 핀

static int __init led_init(void) {
    gpio_request(LED_GPIO, "LED");
    gpio_direction_output(LED_GPIO, 1);
    printk(KERN_INFO "LED ON\n");
    return 0;
}

static void __exit led_exit(void) {
    gpio_set_value(LED_GPIO, 0);
    gpio_free(LED_GPIO);
    printk(KERN_INFO "LED OFF\n");
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Simple LED driver");
MODULE_AUTHOR("You");

(3) 레시피 파일 led-driver.bb

SUMMARY = "Simple LED on/off kernel module"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/GPL-2.0-only;md5=c24b0364c2e3c3253a8d2c95e8d8f6f5"

SRC_URI = "file://led-driver.c"

S = "${WORKDIR}"

inherit module

# 모듈 이름 지정
MODULE_NAME = "led_driver"

do_compile() {
    oe_runmake -C ${KERNEL_SRC} M=${S}
}

do_install() {
    install -d ${D}${base_libdir}/modules/${KERNEL_VERSION}/extra
    install -m 0644 ${S}/led-driver.ko ${D}${base_libdir}/modules/${KERNEL_VERSION}/extra/
}

이렇게 하면 BitBake가 LED 드라이버를 커널 모듈(.ko)로 자동적으로 빌드.


레이어 등록

이제 만든 meta-led를 현재 빌드 환경에 추가.

bitbake-layers add-layer ../meta-led

→ build/conf/bblayers.conf 에 자동으로 추가됨:

BBLAYERS += "${TOPDIR}/../meta-led"

이미지에 포함시키기

이제 빌드할 이미지(core-image-minimal)에 LED 드라이버를 포함시키려면
meta-led/recipes-core/images/core-image-minimal.bbappend 파일을 만듭니다:

IMAGE_INSTALL:append = " led-driver"

→ 이렇게 하면 bitbake core-image-minimal 시 LED 드라이버가 rootfs에 자동 포함됩니다.

결과 이미지(tmp/deploy/images/.../core-image-minimal.wic) 안에는
/lib/modules/<kernel-ver>/extra/led-driver.ko 가 들어있게 됨.

부팅 후 커널 모듈 삽입:

insmod /lib/modules/$(uname -r)/extra/led-driver.ko
dmesg | tail
# "LED ON" 출력 확인

정리

Yocto는 임베디드 리눅스 시스템을 자동으로 빌드해주는 프레임워크로, 툴체인, 커널, 루트파일시스템 등을 통합적으로 관리할 수 있습니다.

이번 실습에서는 Yocto의 레퍼런스 배포판인 Poky를 기반으로 core-image-minimal을 빌드하며,
BitBake 빌드 엔진이 OE-Core의 룰(.conf)에 따라 레시피(.bb)를 실행하는 과정을 직접 경험했습니다.

또한, 레이어(layer) 구조를 통해 기능별 모듈을 쉽게 추가하거나 제거할 수 있었고, LED 드라이버처럼 커스텀 기능을 별도의 레이어로 빌드 환경에 통합할 수도 있었습니다.

커널 빌드 과정은 다소 시간이 걸리고 복잡했지만, Yocto의 구조를 이해하니 전체 빌드 흐름이 자동화되어 있다는 점에서 큰 효율성을 느꼈습니다.

0개의 댓글