Skip to content

Buildroot: package và BR2_EXTERNAL

Trang này trình bày cách đưa phần mềm và tùy biến của dự án vào Buildroot, theo thứ tự: cấu trúc một package, file Config.in, file .mk với các package infrastructure, file .hash, patch, hook, cơ chế BR2_EXTERNAL, và một ví dụ hoàn chỉnh chạy trên QEMU. Khái niệm chung, thư mục output/ và các lệnh build được trình bày ở trang Buildroot.

Nội dung đối chiếu với Buildroot manual của bản LTS 2026.02 (source tag 2026.02.3).

Cấu trúc một package

Mỗi package là một thư mục trong package/ (hoặc trong package/ của một br2-external tree), tên thư mục là tên package viết thường:

File Bắt buộc Vai trò
Config.in Có, với package cho target Khai báo option BR2_PACKAGE_<PKG> và các sub-option trong menuconfig
Config.in.host Chỉ với host package xuất hiện trong menu Khai báo option BR2_PACKAGE_HOST_<PKG>
<pkg>.mk Có Phiên bản, nguồn tải, license, dependency và cách build
<pkg>.hash Có, trừ khi không thể kiểm tra hash (ví dụ source local) Hash của file tải về và của file license
*.patch Không Patch áp vào source sau khi giải nén, theo thứ tự tên file
File khác Không Script init, file cấu hình mẫu, dùng trong .mk qua $(<PKG>_PKGDIR)

Mọi biến trong .mk có tiền tố là tên package viết hoa, dấu - đổi thành _. Ví dụ package my-app dùng tiền tố MY_APP_.

Với package có sẵn trong Buildroot, Config.in của package phải được thêm vào package/Config.in ở đúng nhóm menu. Với package trong br2-external, thêm vào Config.in ở gốc tree (xem BR2_EXTERNAL).

File Config.in

Config.in dùng cú pháp Kconfig, giống Linux kernel:

config BR2_PACKAGE_LIBFOO
    bool "libfoo"
    depends on BR2_TOOLCHAIN_HAS_THREADS
    select BR2_PACKAGE_ZLIB
    help
      Thư viện ví dụ.

      https://example.org/libfoo

if BR2_PACKAGE_LIBFOO

config BR2_PACKAGE_LIBFOO_TOOLS
    bool "install tools"
    help
      Cài thêm các công cụ dòng lệnh của libfoo.

endif

comment "libfoo needs a toolchain w/ threads"
    depends on !BR2_TOOLCHAIN_HAS_THREADS

Quy ước của Buildroot:

  • bool, help và các thuộc tính thụt một tab. Nội dung help thụt một tab và hai dấu cách, kết thúc bằng URL upstream sau một dòng trống.
  • Thứ tự thuộc tính: kiểu và prompt, default, depends on theo target, depends on theo toolchain, depends on theo package khác, select, rồi help.
  • Dùng select cho thư viện mà package cần, depends on cho yêu cầu về toolchain hoặc kiến trúc. Khi dùng depends on, thêm một comment để menuconfig hiện lý do package bị ẩn.

Sub-option đặt trong khối if BR2_PACKAGE_<PKG> ... endif để chỉ hiện khi package được chọn.

File .mk và package infrastructure

File .mk gồm phần metadata (phiên bản, nguồn, license, dependency) và một dòng $(eval $(<infra>-package)) ở cuối. Infrastructure sinh ra toàn bộ rule cho các bước source, extract, patch, configure, build, install. Với build system phổ biến, infrastructure đã biết cách gọi, nên .mk chỉ cần metadata và option.

Infrastructure Dùng cho Option thường dùng
generic-package Makefile viết tay, script <PKG>_BUILD_CMDS, <PKG>_INSTALL_TARGET_CMDS
autotools-package ./configure && make <PKG>_CONF_OPTS, <PKG>_AUTORECONF = YES
cmake-package CMake <PKG>_CONF_OPTS (truyền -D...)
meson-package Meson <PKG>_CONF_OPTS
python-package setuptools, pep517 <PKG>_SETUP_TYPE
golang-package, cargo-package Go, Rust Vendoring dependency khi tải source
kernel-module Module kernel ngoài cây Đi kèm $(eval $(generic-package))
kconfig-package Package cấu hình bằng Kconfig (BusyBox, U-Boot) Sinh các target <pkg>-menuconfig, <pkg>-update-config

Thay -package bằng host-<infra>-package (ví dụ host-generic-package) để build cùng package cho máy build, cài vào output/host/. Package cho máy build có tên với tiền tố host- trong danh sách dependency.

Metadata chung

Biến Ý nghĩa
<PKG>_VERSION Phiên bản, hoặc tag/commit khi tải từ git
<PKG>_SOURCE Tên file tarball, mặc định <pkg>-$(<PKG>_VERSION).tar.gz
<PKG>_SITE URL thư mục chứa tarball, URL repository, hoặc đường dẫn local
<PKG>_SITE_METHOD wget, git, svn, file (tarball local), local (thư mục source local), ... Thường tự suy ra từ SITE
<PKG>_LICENSE, <PKG>_LICENSE_FILES License theo mã SPDX và file chứa nội dung license, dùng cho make legal-info
<PKG>_DEPENDENCIES Package phải build và cài xong trước khi package này configure
<PKG>_INSTALL_STAGING YES để cài vào staging/, cần cho thư viện. Mặc định NO
<PKG>_INSTALL_TARGET NO để không cài vào target/, ví dụ thư viện tĩnh. Mặc định YES

Ví dụ generic-package

################################################################################
#
# libfoo
#
################################################################################

LIBFOO_VERSION = 1.0
LIBFOO_SOURCE = libfoo-$(LIBFOO_VERSION).tar.gz
LIBFOO_SITE = http://www.foosoftware.org/download
LIBFOO_LICENSE = GPL-3.0+
LIBFOO_LICENSE_FILES = COPYING
LIBFOO_INSTALL_STAGING = YES
LIBFOO_DEPENDENCIES = host-libaaa libbbb

define LIBFOO_BUILD_CMDS
    $(MAKE) $(TARGET_CONFIGURE_OPTS) -C $(@D) all
endef

define LIBFOO_INSTALL_STAGING_CMDS
    $(INSTALL) -D -m 0644 $(@D)/foo.h $(STAGING_DIR)/usr/include/foo.h
    $(INSTALL) -D -m 0755 $(@D)/libfoo.so* $(STAGING_DIR)/usr/lib
endef

define LIBFOO_INSTALL_TARGET_CMDS
    $(INSTALL) -D -m 0755 $(@D)/libfoo.so* $(TARGET_DIR)/usr/lib
endef

$(eval $(generic-package))

Ví dụ rút gọn từ tutorial generic-package trong manual. Các biến Buildroot cung cấp trong lệnh:

  • $(@D): thư mục source đã giải nén, output/build/libfoo-1.0/.
  • $(TARGET_CONFIGURE_OPTS): các biến CC, CFLAGS, LDFLAGS, ... trỏ vào cross toolchain.
  • $(STAGING_DIR), $(TARGET_DIR), $(HOST_DIR): các thư mục cài đặt.

Với generic-package, phải tự viết các khối _BUILD_CMDS và _INSTALL_*_CMDS. Với các infrastructure khác, các khối này đã có sẵn và chỉ viết lại khi cần thay đổi hành vi mặc định.

Ví dụ cmake-package

LIBFOO_VERSION = 1.0
LIBFOO_SOURCE = libfoo-$(LIBFOO_VERSION).tar.gz
LIBFOO_SITE = http://www.foosoftware.org/download
LIBFOO_INSTALL_STAGING = YES
LIBFOO_INSTALL_TARGET = NO
LIBFOO_CONF_OPTS = -DBUILD_DEMOS=ON
LIBFOO_DEPENDENCIES = libglib2 host-pkgconf

$(eval $(cmake-package))

Infrastructure tự sinh toolchain file cho CMake và gọi cmake, make, make install với DESTDIR phù hợp. Vì vậy CMakeLists.txt không nên hard-code compiler hay sysroot, xem CMake.

File .hash

File <pkg>.hash chứa hash của tarball và của file license. Mỗi dòng gồm ba trường cách nhau bằng hai dấu cách: loại hash, giá trị hash, tên file.

# Lấy từ trang release của upstream
sha256  0a1b...e9f  libfoo-1.0.tar.gz
# Tự tính
sha256  5c3d...a07  COPYING
  • Loại hash: md5, sha1, sha224, sha256, sha384, sha512. Nếu upstream không công bố hash hoặc chỉ có md5, tự tính ít nhất một hash mạnh (nên dùng sha256) và ghi chú ở dòng comment phía trên.
  • Hash của file license giúp phát hiện license thay đổi khi nâng phiên bản. Hash này được kiểm tra khi chạy make legal-info.
  • Với package tải từ git, Buildroot tạo tarball từ repository với hậu tố định dạng -git4, ví dụ myapp-v1.2.0-git4.tar.gz. Hash trong file .hash là hash của tarball này.

Package dùng SITE_METHOD = local không có tarball nên không cần file hash. Mặc định Buildroot bỏ qua kiểm tra hash với package dùng phiên bản tùy chỉnh (ví dụ kernel với BR2_LINUX_KERNEL_CUSTOM_VERSION). Khi bật BR2_DOWNLOAD_FORCE_CHECK_HASHES, mọi file tải về đều phải có ít nhất một hash hợp lệ.

Patch

Patch của package được áp sau bước extract, theo hai nguồn:

  • Các file *.patch trong thư mục package, theo thứ tự tên file. Nên đặt tên dạng 0001-mo-ta.patch.
  • Thư mục khai báo trong BR2_GLOBAL_PATCH_DIR. Với mỗi thư mục, Buildroot tìm <dir>/<pkg>/<version>/, nếu không có thì <dir>/<pkg>/. Nếu có file series, thứ tự áp patch theo file đó.

BR2_GLOBAL_PATCH_DIR là cách khuyến nghị để thêm patch riêng của dự án cho bất kỳ package nào, kể cả kernel và U-Boot, mà không sửa thư mục package của Buildroot. Package dùng SITE_METHOD = local hoặc <PKG>_OVERRIDE_SRCDIR không được áp patch.

Hook

Hook cho phép chèn lệnh vào trước hoặc sau một bước mà không viết lại cả bước đó. Mỗi bước có cặp biến <PKG>_PRE_<BƯỚC>_HOOKS và <PKG>_POST_<BƯỚC>_HOOKS, với bước là DOWNLOAD, EXTRACT, RSYNC, PATCH, CONFIGURE, BUILD, INSTALL_STAGING, INSTALL_TARGET, INSTALL_IMAGES. Riêng host package dùng INSTALL thay cho INSTALL_STAGING và INSTALL_TARGET

define LIBFOO_REMOVE_DOC
    rm -rf $(TARGET_DIR)/usr/share/doc/libfoo
endef
LIBFOO_POST_INSTALL_TARGET_HOOKS += LIBFOO_REMOVE_DOC

Một số biến tích hợp hệ thống không cần khai báo hook:

Biến Tác dụng
<PKG>_INSTALL_INIT_SYSV Cài script init khi dùng BusyBox init hoặc SysV init
<PKG>_INSTALL_INIT_SYSTEMD Cài unit file khi dùng systemd
<PKG>_USERS Tạo user cho daemon, cùng cú pháp với users table
<PKG>_PERMISSIONS Đặt owner và quyền cho file, cùng cú pháp với device table

Cơ chế BR2_EXTERNAL

Phần tùy biến của dự án (package riêng, defconfig, kernel config, overlay, patch, script) có thể đặt ở hai nơi: sửa trực tiếp trong cây Buildroot và quản lý bằng nhánh git, hoặc đặt trong một thư mục riêng gọi là br2-external tree. Cách thứ hai giữ nguyên cây Buildroot, nên nâng phiên bản Buildroot chỉ cần đổi tag.

Cấu trúc br2-external tree

Ba file bắt buộc, có thể để rỗng:

File Nội dung
external.desc name: (bắt buộc, chỉ gồm [A-Za-z0-9_]) và desc: (mô tả ngắn)
Config.in source các Config.in của package, option riêng của dự án. Hiện trong menu External options
external.mk include các file .mk của package, target make riêng

Các thư mục tùy chọn:

Thư mục Vai trò
configs/ Defconfig của dự án, hiện trong make list-defconfigs dưới nhãn External configs. Defconfig trùng tên với Buildroot thì bản trong br2-external được dùng
package/ Package riêng, cùng cấu trúc với package của Buildroot
board/ Nội dung tự do: kernel config, overlay, script post-build và post-image
patches/ Dùng làm BR2_GLOBAL_PATCH_DIR
provides/ Thêm lựa chọn cho các mục có nhiều implementation: toolchain, init system, skeleton, jpeg, openssl
linux/ Linux kernel extension bổ sung

Từ name: trong external.desc, Buildroot sinh biến BR2_EXTERNAL_<NAME>_PATH chứa đường dẫn tuyệt đối của tree. Biến này dùng được trong Kconfig, trong Makefile, trong defconfig và trong các script post-build, post-image. Mọi đường dẫn tới file của dự án nên viết qua biến này để tree đặt ở đâu cũng được.

Sử dụng

make BR2_EXTERNAL=/path/to/br2-ext menuconfig

Giá trị BR2_EXTERNAL được lưu vào file .br2-external.mk trong thư mục output, nên các lệnh make sau không cần truyền lại. Dùng nhiều tree bằng danh sách cách nhau bởi dấu cách, bỏ tree bằng BR2_EXTERNAL= (rỗng). Đường dẫn tương đối được tính từ thư mục gốc của Buildroot, không phải thư mục output.

Cách tổ chức repository thường gặp là một repository dự án chứa br2-external tree và Buildroot dưới dạng git submodule, cố định ở một tag LTS. Defconfig, kernel config, overlay và patch đều nằm trong repository dự án.

Ví dụ hoàn chỉnh trên QEMU

Ví dụ tạo một br2-external tree tên VUX gồm package hello (C, Makefile viết tay, source nằm ngay trong tree) và một defconfig dựa trên qemu_aarch64_virt_defconfig ở trang Buildroot, có thêm rootfs overlay.

Chưa chạy thử

Ví dụ được viết theo manual và đối chiếu với file trong source Buildroot 2026.02.3, nhưng chưa được build và chạy thử trong môi trường viết trang.

br2-ext/
├── external.desc
├── Config.in
├── external.mk
├── configs/
│   └── vux_qemu_aarch64_defconfig
├── board/
│   └── vux-qemu/
│       └── rootfs-overlay/
│           └── etc/
│               └── motd
└── package/
    └── hello/
        ├── Config.in
        ├── hello.mk
        └── src/
            ├── Makefile
            └── hello.c

File của tree

external.desc:

name: VUX
desc: Vux example br2-external tree

Config.in:

source "$BR2_EXTERNAL_VUX_PATH/package/hello/Config.in"

external.mk:

include $(sort $(wildcard $(BR2_EXTERNAL_VUX_PATH)/package/*/*.mk))

Package hello

package/hello/Config.in:

config BR2_PACKAGE_HELLO
    bool "hello"
    help
      Chương trình hello world ví dụ, build bằng Makefile viết tay.

package/hello/hello.mk:

################################################################################
#
# hello
#
################################################################################

HELLO_VERSION = 1.0
HELLO_SITE = $(BR2_EXTERNAL_VUX_PATH)/package/hello/src
HELLO_SITE_METHOD = local
HELLO_LICENSE = MIT

define HELLO_BUILD_CMDS
    $(MAKE) $(TARGET_CONFIGURE_OPTS) -C $(@D)
endef

define HELLO_INSTALL_TARGET_CMDS
    $(INSTALL) -D -m 0755 $(@D)/hello $(TARGET_DIR)/usr/bin/hello
endef

$(eval $(generic-package))

package/hello/src/hello.c:

#include <stdio.h>

int main(void)
{
    printf("Hello from Buildroot\n");
    return 0;
}

package/hello/src/Makefile dùng CC, CFLAGS, LDFLAGS do $(TARGET_CONFIGURE_OPTS) truyền vào, nên không cần biết cross compiler là gì:

hello: hello.c
    $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<

clean:
    rm -f hello

Với SITE_METHOD = local, Buildroot copy thư mục src/ vào output/build/hello-1.0/ bằng rsync thay vì tải tarball. Cách này phù hợp với code nằm cùng repository dự án. Source ở repository riêng thì dùng SITE_METHOD = git kèm file .hash.

Defconfig và overlay

configs/vux_qemu_aarch64_defconfig lấy lại các dòng của qemu_aarch64_virt_defconfig, bỏ phần build QEMU và post-image script, thêm overlay và package hello:

BR2_aarch64=y
BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_6_18=y
BR2_SYSTEM_DHCP="eth0"
BR2_ROOTFS_OVERLAY="$(BR2_EXTERNAL_VUX_PATH)/board/vux-qemu/rootfs-overlay"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.18.7"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/qemu/aarch64-virt/linux.config"
BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y
BR2_TARGET_ROOTFS_EXT2=y
BR2_TARGET_ROOTFS_EXT2_4=y
# BR2_TARGET_ROOTFS_TAR is not set
BR2_PACKAGE_HELLO=y

Đường dẫn kernel config board/qemu/... là đường dẫn tương đối tính từ gốc Buildroot, dùng lại config của board QEMU. Trong dự án thực tế, copy file này vào board/vux-qemu/ của tree và trỏ qua $(BR2_EXTERNAL_VUX_PATH).

board/vux-qemu/rootfs-overlay/etc/motd:

Vux QEMU image built with Buildroot

Build và chạy

cd buildroot
make BR2_EXTERNAL=../br2-ext O=../output-vux vux_qemu_aarch64_defconfig
cd ../output-vux
make

Defconfig không build QEMU nên dùng QEMU của máy build (gói qemu-system-arm trên Debian/Ubuntu):

qemu-system-aarch64 -M virt -cpu cortex-a53 -nographic -smp 1 \
  -kernel images/Image \
  -append "rootwait root=/dev/vda console=ttyAMA0" \
  -netdev user,id=eth0 -device virtio-net-device,netdev=eth0 \
  -drive file=images/rootfs.ext4,if=none,format=raw,id=hd0 \
  -device virtio-blk-device,drive=hd0

Sau khi đăng nhập root, nội dung /etc/motd hiện ra và lệnh hello in Hello from Buildroot.

Vòng lặp sửa code của package hello:

# sau khi sửa src/hello.c
make hello-rebuild all

hello-rebuild rsync lại source, build và cài lại vào target/; all tạo lại rootfs.ext4. Sửa .mk hoặc Config.in của package thì dùng make hello-dirclean all. Sau khi chỉnh cấu hình bằng make menuconfig, lưu lại vào tree bằng:

make savedefconfig BR2_DEFCONFIG=../br2-ext/configs/vux_qemu_aarch64_defconfig

Kiểm tra package

Công cụ Tác dụng
utils/check-package Kiểm tra coding style của Config.in, .mk, .hash, patch. Với br2-external dùng check-package -b <đường dẫn>/*. Cần shellcheck, flake8, python-magic
utils/test-pkg Build package với nhiều toolchain dựng sẵn (glibc, musl, uClibc-ng, nhiều kiến trúc) để phát hiện lỗi phụ thuộc toolchain. Đầu vào là một đoạn cấu hình, ví dụ ./utils/test-pkg -c libfoo.config -p libfoo
make <pkg>-show-info In metadata của package dạng JSON
make legal-info Kiểm tra license và hash của file license

Liên quan

  • Buildroot: tổng quan, thư mục output, các lệnh build và phát triển.
  • Yocto: recipe và layer, khái niệm tương ứng với package và br2-external.
  • CMake và Makefile (Programming): build system mà các package infrastructure gọi tới.
  • Gói mã nguồn mở: đánh giá và tích hợp gói mã nguồn mở vào image.

Tài liệu tham khảo