Yocto Project không phải distro: build Linux đầu tiên
Hướng dẫn Yocto Project cho người mới: hiểu Poky, BitBake, layers, recipes, build image Linux chạy QEMU, tùy chỉnh image và tạo layer riêng.
Lần đầu mình mở tài liệu Yocto Project, mình tưởng mình đang đọc luật thuế.
Nó phức tạp điên và nó đắt điên (50GB và khi build thì cháy máy).
Một đống thuật ngữ - Poky, BitBake, OpenEmbedded, layer, recipe, local.conf, bblayers.conf, IMAGE_INSTALL, do_compile, SRC_URI - bay vào mặt như một trận bão Scrabble. Mình nhìn câu lệnh bitbake core-image-minimal, tự hỏi: "Core image minimal của cái gì? Và tại sao nó cần 50GB đĩa cứng?"
Đó là vào năm 2019. Mình đang làm việc với một board ARM cũ, cần một hệ điều hành Linux tối giản để chạy một service duy nhất. Lựa chọn đầu tiên của mình là lấy một bản Ubuntu Server ARM, gỡ bỏ mọi thứ không cần, rồi copy lên board. Nó chạy. Rồi sau đó không chạy nữa. Rồi mình không nhớ mình đã gỡ cái gì. Rồi đồng nghiệp build lại từ đầu trên một máy khác và ra một kết quả khác.
Mình mới hiểu tại sao người ta cần Yocto.

Tóm tắt nhanh
- Yocto Project không phải là một Linux distribution. Nó là một bộ công cụ và metadata để bạn tự đóng một distribution cho riêng mình.
- Bốn trụ cột: Poky (bộ starter kit), BitBake (task scheduler), Layers (cách tổ chức kiến thức), Recipes (công thức build từng phần mềm).
- Output: một file image (
.wic,.ext4,.tar.bz2, v.v.) có thể flash lên board hoặc chạy trên QEMU. - Bài viết này sẽ đưa bạn từ lý do tồn tại của Yocto, qua kiến trúc, so sánh với các lựa chọn thay thế, đến chỗ tự build một image Linux chạy được trên QEMU - và thêm một package của riêng bạn vào đó.
- Yêu cầu: máy Linux (Ubuntu/Debian khuyên dùng), ít nhất 50–100GB đĩa trống, 8GB RAM tối thiểu, 16GB+ sẽ thoải mái hơn nhiều.
1. Vấn đề Yocto giải quyết: tại sao không dùng Ubuntu Server luôn?
Yocto giải quyết bài toán tạo một Linux distribution tùy chỉnh, reproducible, và tối ưu cho một phần cứng cụ thể. Thay vì lấy distro có sẵn rồi cắt bớt, bạn khai báo từ đầu: kernel nào, package nào, config nào - rồi máy build tự động tạo ra image giống hệt nhau mỗi lần.
Câu hỏi này nghe giống như hỏi "tại sao không mua sẵn một chiếc xe đạp mà phải tự lắp?". Câu trả lởi phụ thuộc vào bạn cần gì.
Nếu bạn đang làm prototype nhanh trên Raspberry Pi, mua một chiếc xe đạp có sẵn (Raspberry Pi OS, Ubuntu Server) là lựa chọn đúng đắn. Nhưng nếu bạn đang xây một sản phẩm embedded cần chạy 24/7 trong 5–10 năm, chi phí của việc "mua sẵn" rất nhanh sẽ vượt quá chi phí "tự lắp".
Đây là những vấn đề mình gặp khi dùng distro có sẵn:
Thứ nhất, nó chứa quá nhiều thứ bạn không cần. Một bản Ubuntu Server ARM có thể chiếm vài GB. Yocto cho phép bạn build một image chỉ vài chục MB nếu bạn chỉ cần kernel + busybox + một service. Trên embedded, mỗi MB flash đều có giá tiền.
Thứ hai, nó không reproducible. Bạn cài apt update && apt upgrade hôm nay, rồi đồng nghiệp làm điều tương tự tuần sau, hai hệ thống có thể khác nhau. Trong sản xuất, "cùng một input phải cho cùng một output" không phải là luxury - nó là yêu cầu cơ bản.
Thứ ba, nó không được đo ni đóng giày cho phần cứng của bạn. Distro chung chạy trên hàng triệu loại board. Nhưng board của bạn có thể có một GPIO chip lạ, một sensor cần driver tùy chỉnh, hoặc một bootloader đặc biệt. Yocto cho phép bạn điều chỉnh từng lớp: bootloader, kernel config, rootfs, package list.
Thứ tư, maintain lâu dài khó. Distro upstream có thể drop support cho một phiên bản kernel, hoặc thay đổi cách init system hoạt động. Với Yocto, bạn có thể pin một LTS release (hiện tại là 5.0 "Scarthgap", support đến 30 Apr 2028) và kiểm soát mọi thay đổi qua version control.
Nhưng điều quan trọng là: Yocto không phải lúc nào cũng đúng. Nếu bạn chỉ cần một Raspberry Pi chạy Home Assistant, đừng dùng Yocto. Nếu bạn cần một firmware cho sản phẩm IoT sắp đưa ra factory, Yocto là một trong những lựa chọn nghiêm túc nhất.
2. Bốn trụ cột của Yocto
Bốn trụ cột của Yocto là Poky, BitBake, Layers, và Recipes. Poky là bộ starter kit; BitBake là task scheduler; Layers là cách tổ chức metadata; Recipes là công thức build từng phần mềm. Cả bốn cùng tạo ra image Linux cuối cùng.
Mình thường hình dung Yocto như một nhà máy đóng gói đồ ăn theo đơn hàng. Bốn thành phần chính như sau:

2.1. Poky - nhà máy mẫu
Poky là reference distribution của Yocto. Nói đơn giản, đây là một bộ starter kit đã bao gồm sẵn:
- BitBake - task scheduler.
- OpenEmbedded-Core (OE-Core) - metadata cho hàng nghìn recipes cơ bản.
- meta-yocto - các cấu hình mặc định cho reference distro.
Khi bạn clone git://git.yoctoproject.org/poky.git, bạn đang lấy về toàn bộ nhà máy mẫu này. Hầu hết người mới bắt đầu từ Poky, sau đó thêm các layer khác cho nhu cầu cụ thể.
2.2. BitBake - quản lý dây chuyền
BitBake là công cụ đọc recipes, tính toán dependency, và chạy các tasks theo đúng thứ tự. Bạn có thể nghĩ nó như make nhưng hiểu được dependency ở cấp "gói phần mềm" thay vì chỉ "file object".
Ví dụ: nếu bạn muốn build htop, BitBake sẽ thấy rằng htop phụ thuộc vào ncurses. Nó sẽ build ncurses trước. Nếu ncurses phụ thuộc vào toolchain, nó build toolchain trước nữa. Tất cả tự động.
Một điểm hay của BitBake: nó có nhớ. Nếu bạn đã build ncurses rồi, lần sau nó sẽ dùng lại thay vì build lại từ đầu. Đây là lý do build lần đầu mất vài giờ, nhưng build lần hai chỉ mất vài phút.
2.3. Layers - các khu chuyên môn
Layer là cách Yocto tổ chức kiến thức. Mỗi layer là một thư mục có tên bắt đầu bằng meta-, chứa các recipes, classes, và configs cho một mục đích.
Một số layer phổ biến:
| Layer | Mục đích |
|---|---|
meta-raspberrypi |
Hỗ trợ board Raspberry Pi |
meta-openembedded |
Hàng nghìn recipes bổ sung (networking, python, multimedia...) |
meta-virtualization |
Docker, container trên embedded |
meta-security |
Các tính năng bảo mật |
meta-mylayer |
Layer của bạn, cho sản phẩm của bạn |
Layers cho phép bạn "mix and match". Bạn lấy layer BSP của nhà sản xuất board, layer ứng dụng của team, layer bảo mật của công ty - tất cả cùng build thành một image.
2.4. Recipes - công thức nấu ăn
Recipe là file .bb mô tả cách build một phần mềm cụ thể. Nó giống như một công thức nấu ăn có đầy đủ nguyên liệu và các bước:
SUMMARY = "A friendly hello-world program"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://hello.c"
S = "${WORKDIR}"
do_compile() {
${CC} hello.c -o hello ${LDFLAGS}
}
do_install() {
install -d ${D}${bindir}
install -m 0755 hello ${D}${bindir}/hello
}
Một recipe thường có các phần:
SUMMARY,LICENSE: metadata.SRC_URI: nguồn code (git, tarball, local file).DEPENDS: các package cần có trước khi build.do_fetch,do_unpack,do_patch,do_configure,do_compile,do_install: các tasks BitBake sẽ chạy.
Bạn không cần nhớ hết. Nhưng cần hiểu: mọi thứ trong Yocto đều là metadata. Code C nằm ở một nơi, cách build nó nằm ở recipe, cách kết hợp thành image nằm ở image recipe khác.
3. Các lựa chọn thay thế Yocto
Các lựa chọn thay thế Yocto gồm Buildroot (đơn giản hơn), distro có sẵn (Raspberry Pi OS, Armbian, Ubuntu Server), các nền tảng thương mại (PetaLinux, Wind River, Timesys), và các hệ thống declarative như NixOS / GNU Guix. Lựa chọn đúng phụ thuộc vào quy mô, reproducibility, và ngân sách support.
Trước khi bạn commit với Yocto, đáng để biết có những lựa chọn khác. Mình không muốn bạn học Yocto rồi sau đó nhận ra Buildroot đã đủ.
Buildroot là người anh em họ gần nhất. Nó cũng build embedded Linux từ source, nhưng triết lý khác: đơn giản hơn, ít metadata hơn, build nhanh hơn. Nếu bạn chỉ cần một hệ thống tối giản và không cần package management phức tạp, Buildroot có thể là lựa chọn tốt hơn. Nhược điểm: ít linh hoạt hơn Yocto khi dự án lớn dần, không có package feeds, và khó maintain khi cần nhiều biến thể sản phẩm.
Distro có sẵn (Raspberry Pi OS, Armbian, Ubuntu Server) là cách nhanh nhất để có một hệ thống chạy được. Nếu mục tiêu là prototype trong vài giờ hoặc chạy một ứng dụng có sẵn, đừng tự làm khó mình. Nhược điểm: bloat, thiếu reproducibility, khó customize sâu. Nếu bạn muốn hiểu rõ hơn về cách Linux tương tác với phần cứng ở cấp driver, bài viết về device driver trong embedded Linux của mình có thể là điểm khởi đầu tốt.
PetaLinux / Wind River Linux / Timesys là các lựa chọn thương mại. Chúng thường đi kèm support, BSP sẵn cho phần cứng đặc thù (đặc biệt FPGA SoC), và tooling hoàn thiện. Chi phí là rào cản, cùng với vendor lock-in.
NixOS / GNU Guix là lối thoát hiện đại cho vấn đề reproducibility. Cả hai đều khai báo toàn bộ dependency một cách nghiêm ngặt. Mình thấy tiềm năng, nhưng ecosystem embedded vẫn nhỏ hơn Yocto nhiều.
Nếu bạn đang đọc bài này, có lẽ bạn đã loại bỏ các distro có sẵn và muốn một framework build nghiêm túc. Giữa Yocto và Buildroot, câu hỏi thường là: dự án của bạn sẽ lớn đến mức nào trong 2-3 năm tới? Nếu câu trả lởi là "rất lớn, nhiều package, nhiều biến thể", Yocto là cược an toàn hơn. Nếu là "một board, một ứng dụng, tối giản", Buildroot đáng thử trước.
4. Chuẩn bị môi trường
Để build Yocto bạn cần máy Linux (Ubuntu/Debian khuyên dùng), ít nhất 50–100GB đĩa trống, 8GB RAM tối thiểu (16GB+ thoải mái hơn), và kết nối Internet ổn định. Build lần đầu sẽ tải về và biên dịch hàng GB source code.
Trước khi build, hãy kiểm tra:
- OS: Ubuntu 22.04/24.04 hoặc Debian 12 khuyên dùng. Yocto officially support một số distro; nếu dùng distro khác, bạn có thể cần tự xử lý thêm.
- Đĩa cứng: ít nhất 50–100GB trống. Build Yocto tạo ra rất nhiều file tạm.
- RAM: 8GB tối thiểu, 16GB+ thoải mái hơn. Build GCC và kernel đòi hỏi bộ nhớ.
- Mạng: ổn định, vì lần đầu Yocto sẽ tải về rất nhiều source code từ internet.
Cài dependencies trên Ubuntu/Debian:
sudo apt update
sudo apt install -y gawk wget git diffstat unzip texinfo \
gcc build-essential chrpath socat cpio python3 python3-pip \
python3-pexpect xz-utils debianutils iputils-ping \
libsdl1.2-dev xterm zstd liblz4-tool qemu-system-arm qemu-system-x86
Nếu bạn dùng Ubuntu 24.04, có thể cần thêm make và một số gói khác; Yocto sẽ báo lỗi rõ nếu thiếu.
5. Hands-on 1: Build Linux đầu tiên chạy trên QEMU
Để build Linux đầu tiên với Yocto, clone Poky Scarthgap, khởi tạo build environment, chọn MACHINE = "qemuarm64", rồi chạy bitbake core-image-minimal. Sau khi build xong, runqemu qemuarm64 nographic sẽ boot image trên máy ảo.
Chúng ta sẽ build core-image-minimal - image tối thiểu của Yocto - và chạy nó trên QEMU. Lý do chọn QEMU thay vì Raspberry Pi: bạn không cần phần cứng.

5.1. Clone Poky
Ở thời diểm viết bài, LTS đang được khuyên dùng là 5.0 Scarthgap (support đến Apr 2028). Hãy đảm bảo dùng branch đúng:
mkdir -p ~/yocto && cd ~/yocto
git clone -b scarthgap git://git.yoctoproject.org/poky.git
Nếu máy bạn không vào được git:// (do firewall), dùng https://:
git clone -b scarthgap https://git.yoctoproject.org/poky.git
5.2. Khởi tạo build environment
cd poky
source oe-init-build-env
Lệnh này làm ba việc:
- Tạo thư mục
build/nếu chưa có. - Sao chép các file config mẫu vào
build/conf/. - Đưa bạn vào thư mục
build/và thiết lập các biến môi trường cần thiết.
Sau khi chạy, prompt của bạn sẽ đổi thành một cái gì đó như:
### Shell environment set up for builds. ###
You can now run 'bitbake <target>'
Common targets are:
core-image-minimal
core-image-full-cmdline
core-image-weston
core-image-sato
meta-toolchain
meta-ide-support
5.3. Cấu hình machine
Mở conf/local.conf và sửa dòng:
MACHINE ??= "qemux86-64"
thành:
MACHINE ??= "qemuarm64"
qemuarm64 là một máy ảo ARM 64-bit. Bạn cũng có thể dùng qemux86-64 nếu muốn x86, nhưng mình thích ARM vì nó gần với thế giới embedded hơn.
5.4. Build image
Bây giờ, lệnh quan trọng:
bitbake core-image-minimal
Lần đầu chạy, BitBake sẽ:
- Parse toàn bộ recipes trong Poky.
- Tải source code cho toolchain, kernel, busybox, v.v.
- Build cross-compiler.
- Build kernel.
- Build root filesystem.
- Tạo image cuối cùng.
Tùy máy, quá trình này mất từ 1 đến 4 giờ. Đừng lo. Lần sau sẽ nhanh hơn nhiều.
Nếu build bị gián đoạn (mất điện, mất mạng), bạn chỉ cần chạy lại bitbake core-image-minimal. BitBake sẽ tiếp tục từ chỗ dừng.
5.5. Chạy trên QEMU
Sau khi build xong, chạy:
runqemu qemuarm64 nographic
Một vài phút sau, bạn sẽ thấy dòng chữ:
Poky (Yocto Project Reference Distro) 5.0 qemuarm64 /dev/hvc0
qemuarm64 login:
Đăng nhập bằng root (không cần password). Bạn đang ở bên trong một Linux mà bạn tự build.
Thử một vài lệnh:
uname -a
cat /etc/os-release
free -h
ps
Bạn sẽ thấy kernel Yocto, rootfs tối giản, và chỉ vài process đang chạy. Đó là vẻ đẹp của core-image-minimal: nó chỉ có những gì bạn thực sự cần.
Để thoát QEMU, nhấn Ctrl+A rồi X.
5.6. Output nằm ở đâu?
Các file image nằm trong:
tmp/deploy/images/qemuarm64/
Bạn sẽ thấy các file như:
core-image-minimal-qemuarm64.rootfs.wic.bz2- image sẵn sàng flash.core-image-minimal-qemuarm64.rootfs.tar.bz2- rootfs dạng tarball.core-image-minimal-qemuarm64.rootfs.ext4- rootfs dạng ext4.zImagehoặcImage- kernel.
6. Hands-on 2: Tùy chỉnh image
Để tùy chỉnh image trong Yocto, bạn sửa conf/local.conf: thêm package qua IMAGE_INSTALL:append, đổi hostname qua hostname, bật feature qua EXTRA_IMAGE_FEATURES, rồi build lại bằng bitbake core-image-minimal.
Bây giờ chúng ta sẽ thêm htop vào image. Cách làm: mở conf/local.conf, thêm dòng:
IMAGE_INSTALL:append = " htop"
Lưu ý dấu cách trước htop. Trong BitBake, :append nối chuỗi vào cuối giá trị hiện có. Nếu thiếu dấu cách, bạn sẽ có "htop" dính liền với package trước đó, gây lỗi.
Build lại:
bitbake core-image-minimal
Lần này build nhanh hơn nhiều vì toolchain và kernel đã có sẵn. Chạy QEMU lại và kiểm tra:
which htop
htop
Bạn cũng có thể thêm nhiều package cùng lúc:
IMAGE_INSTALL:append = " htop nano curl"
Đổi hostname:
hostname = "my-yocto-box"
Bật một số tính năng hữu ích cho debug:
EXTRA_IMAGE_FEATURES ?= "debug-tweaks"
debug-tweaks cho phép root login không password, cài ssh, và một số tiện ích khác. Đừng dùng nó trên image production.
7. Hands-on 3: Tạo layer và recipe đơn giản
Để tạo layer riêng trong Yocto, chạy bitbake-layers create-layer ../meta-mylayer, thêm layer bằng bitbake-layers add-layer ../meta-mylayer, rồi tạo recipe trong meta-mylayer/recipes-example/hello/. Đây là cách bạn đóng gói ứng dụng của riêng mình thay vì chỉ dùng package có sẵn.
Đây là phần quan trọng nhất: đưa code của bạn vào Yocto. Chúng ta sẽ tạo một layer đơn giản chứa một chương trình "hello world" viết bằng C.
7.1. Tạo layer
Từ thư mục build/:
bitbake-layers create-layer ../meta-mylayer
bitbake-layers add-layer ../meta-mylayer
Lệnh đầu tiên tạo cấu trúc thư mục layer. Lệnh thứ hai ghi layer vào conf/bblayers.conf.
Cấu trúc layer mới:
meta-mylayer/
├── conf/
│ └── layer.conf
├── recipes-example/
│ └── example/
│ └── example_0.1.bb
└── COPYING.MIT
7.2. Viết recipe hello
Tạo thư mục:
mkdir -p ../meta-mylayer/recipes-example/hello/files
Tạo file hello.c:
#include <stdio.h>
int main() {
printf("Hello from my custom Yocto layer!\n");
return 0;
}
Tạo recipe ../meta-mylayer/recipes-example/hello/hello_1.0.bb:
SUMMARY = "Hello from my layer"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://hello.c"
S = "${WORKDIR}"
do_compile() {
${CC} hello.c -o hello ${LDFLAGS}
}
do_install() {
install -d ${D}${bindir}
install -m 0755 hello ${D}${bindir}/hello
}
7.3. Thêm package vào image
Mở conf/local.conf, thêm:
IMAGE_INSTALL:append = " hello"
Build lại:
bitbake core-image-minimal
Chạy QEMU và thử:
hello
Nếu mọi thứ đúng, bạn sẽ thấy:
Hello from my custom Yocto layer!
Đây là khoảnh khắc mình thích nhất: bạn không còn là người xem từ ngoài. Bạn đã đưa code của mình vào dây chuyền sản xuất Linux.
8. Những lỗi thường gặp và cách sống sót
Các lỗi thường gặp khi build Yocto gồm thiếu dependency hệ thống, MACHINE không khớp layer, branch layer không đồng bộ, fetch fail do mạng, và đầy đĩa. Công cụ hữu ích để debug là bitbake -e <recipe> xem biến, và bitbake -c cleansstate <recipe> để xóa cache build của một recipe.
Yocto có tiếng khó. Phần lớn là do build lần đầu dài và lỗi xuất hiện muộn. Dưới đây là những vấn đề mình gặp nhiều nhất.
8.1. Thiếu dependency hệ thống
Nếu build fail ngay đầu với lỗi kiểu "command not found" hoặc "missing package", hãy kiểm tra lại danh sách dependencies. Yocto sẽ báo cụ thể thiếu gì.
8.2. MACHINE không khớp layer
Nếu bạn dùng layer BSP (vd meta-raspberrypi) nhưng MACHINE set sai, BitBake sẽ không tìm được kernel config hay bootloader phù hợp. Kiểm tra lại tên machine trong tài liệu layer.
8.3. Branch/release của layer không đồng bộ
Nếu Poky là scarthgap nhưng layer bạn thêm là kirkstone hoặc master, bạn sẽ gặp lỗi parse recipe. Luôn dùng cùng release cho tất cả các layer.
8.4. do_fetch fail
Lỗi này thường do mạng, proxy, hoặc upstream repository thay đổi. Bạn có thể thử:
bitbake <recipe> -c fetch
Hoặc kiểm tra file tmp/work/.../temp/log.do_fetch.
8.5. Disk full
Build Yocto dễ chiếm 50-100GB. Nếu đĩa đầy, build fail với lỗi "No space left on device". Giải pháp: xóa tmp/ hoặc build trên partition lớn hơn. Nhớ rằng xóa tmp/ sẽ mất cache và build lại từ đầu.
8.6. Công cụ debug hữu ích
# Xem toàn bộ biến của một recipe
bitbake -e hello
# Xóa trạng thái build của một recipe (giữ shared state)
bitbake hello -c cleansstate
# Xem task list của một recipe
bitbake -c listtasks hello
9. Kết luận
Yocto Project là một framework để build Linux distribution tùy chỉnh, không phải là một distro có sẵn. Nếu bạn nắm được bốn trụ cột Poky, BitBake, layers, và recipes, bạn đã có bản đồ để tự build image Linux chạy được trên QEMU, tùy chỉnh nó qua local.conf, và đưa code riêng vào qua layer tự tạo.
Sau khi đi qua bài viết này, bạn đã:
- Hiểu tại sao distro có sẵn không phải lúc nào cũng đủ.
- Biết Yocto khác Buildroot, distro có sẵn, và các lựa chọn thương mại như thế nào.
- Nắm được bốn trụ cột: Poky, BitBake, layers, recipes.
- Tự build được
core-image-minimalchạy trên QEMU. - Thêm package vào image qua
IMAGE_INSTALL:append. - Tạo layer và recipe đơn giản.
Yocto vẫn phức tạp. Nó vẫn đòi 50GB và vẫn khiến máy nóng lên khi build. Nhưng giờ bạn đã có một bản đồ, không còn lạc trong rừng thuật ngữ nữa.
Bước tiếp theo của mình thường là thử với một board thật - Raspberry Pi, hoặc một board ARM công nghiệp. Hoặc đọc tiếp BitBake User Manual để hiểu sâu hơn về metadata language. Hoặc thử devtool, công cụ giúp phát triển recipe nhanh hơn nhiều.
Bạn sẽ chọn hướng nào?
Bài viết được viết dựa trên Yocto Project 5.0 "Scarthgap" (LTS đến 30 Apr 2028). Các lệnh và đường dẫn có thể thay đổi theo release; hãy kiểm tra tài liệu chính thức nếu bạn dùng phiên bản khác.