ESC
输入关键词搜索文章标题和内容

嵌入式Linux构建系统全解:Buildroot vs Yocto vs OpenWrt

本文由 linuxROS 整理发布,首发于 linuxros.cn,转载请注明出处。

嵌入式Linux构建系统全解:Buildroot vs Yocto vs OpenWrt

导读:做嵌入式产品,系统从哪来?Buildroot十分钟出镜像,Yocto搞定企业定制,OpenWrt是路由器标配。三大构建系统怎么选,看这篇就够了。


一、原理简析

嵌入式Linux系统是什么?

嵌入式Linux本质上是五个部件的组装:Bootloader + 内核 + 根文件系统 + 驱动 + 应用。

部件 作用 类比
Bootloader 上电先跑,初始化硬件,加载内核 开机自检
内核 管理CPU/内存/外设,提供系统调用 操作系统核心
根文件系统 存放命令、库、配置 /bin /lib /etc
驱动 让内核认识具体硬件 硬件抽象层
应用 跑业务逻辑 产品功能

为什么要用构建系统?

手工处理交叉编译、库依赖、版本兼容,能把人逼疯。构建系统的作用就是一键搞定:下载、打补丁、配置、编译、打包。

一个命令出镜像,不用操心细节。

交叉编译是什么?

嵌入式CPU(ARM/RISC-V)和电脑(x86)指令集不同。交叉编译就是在电脑上编译能在嵌入式设备上运行的程序。

本质:宿主机x86 → 目标机ARM 的编译。

三大构建系统均内置工具链自动维护功能,Buildroot默认构建内部工具链,Yocto使用OpenEmbedded自动下载配置工具链,OpenWrt自带gcc。绝大多数场景无需手动安装交叉编译器。

三大构建系统的定位

系统 本质 定位 一句话理解
Buildroot 固件生成器 简单快速 傻瓜相机,按下就拍
Yocto 元发行版框架 企业级定制 专业单反,想怎么调就怎么调
OpenWrt 路由器专用系统 网络设备 路由器里的瑞士军刀

二、核心架构对比

构建系统架构图

flowchart TB subgraph 用户层["用户操作"] 配置["make menuconfig<br/>图形化配置"] 写脚本["编写脚本/Recipe"] end subgraph 构建系统["构建系统核心"] BR["Buildroot<br/>Kconfig + Makefile"] YP["Yocto<br/>BitBake + Layer"] OW["OpenWrt<br/>UCI + procd"] end subgraph 输出["构建产物"] 镜像["固件镜像<br/>rootfs.img"] 包["软件包<br/>ipk/deb/rpm"] SDK["交叉编译工具链<br/>SDK"] end subgraph 目标["目标系统"] Boot["Bootloader"] Kernel["Linux内核"] Rootfs["根文件系统"] App["应用程序"] end 配置 --> BR 写脚本 --> YP 写脚本 --> OW BR --> 镜像 YP --> 镜像 YP --> 包 YP --> SDK OW --> 镜像 OW --> 包 镜像 --> Boot 镜像 --> Kernel 镜像 --> Rootfs 镜像 --> App style 用户层 fill:#FFF8E1,stroke:#F57C00 style 构建系统 fill:#E3F2FD,stroke:#1976D2 style 输出 fill:#E8F5E9,stroke:#388E3C style 目标 fill:#F3E5F5,stroke:#7B1FA2

Buildroot架构

Buildroot的架构最简单,核心就是Kconfig配置 + Makefile构建。你用make menuconfig选组件,Buildroot自动下载、编译、打包。

Buildroot/
├── Config.in              # 顶层配置入口
├── Makefile               # 主构建逻辑
├── package/              # 软件包目录(每个软件包一个子目录)
│   ├── hello/
│   │   ├── Config.in      # 包配置选项
│   │   └── hello.mk      # 包构建规则
│   └── python3/
├── system/                # 系统骨架(rootfs模板)
└── output/                # 构建输出目录
    ├── build/            # 源码解压目录
    ├── host/             # 交叉工具链
    ├── images/           # 最终镜像
    └── target/          # 根文件系统(未打包)

Buildroot的设计哲学:简单至上。所有东西都在一个仓库里,配置一目了然。

Yocto架构

Yocto是层(Layer)叠层的设计,最强大也最复杂。核心组件:

组件 作用 类比
BitBake 构建引擎,解析Recipe执行任务 厨房里的炒菜机器人
Poky Yocto的参考发行版,含BitBake+OE-Core 官方食谱
OpenEmbedded-Core 基础元数据层,提供通用recipes 食材库
Meta-Layer 可叠加的配置层,BSP/应用/中间件 插件
yocto-project/
├── poky/
│   ├── bitbake/          # 构建引擎
│   ├── meta/             # OE-Core基础层
│   └── meta-poky/        # Poky参考层
├── meta-openembedded/    # 大量软件包
├── meta-qt5/             # Qt5支持层
├── meta-rockchip/        # RK平台BSP层
└── your-meta-layer/      # 你的自定义层

Layer的工作原理:每个Layer就像一个插件,叠加到主系统上。Rockchip的meta-rockchip提供板级支持,你的meta-yourproduct提供产品定制,互不干扰。

OpenWrt架构

OpenWrt专为路由器设计,核心是UCI配置系统 + procd初始化。

来自 linuxros.cn · linuxROS
组件 作用 类比
UCI(Unified Configuration Interface) 统一配置接口,/etc/config/下的配置文件 路由器的"设置菜单"
procd 进程管理,替代systemd 路由器的"进程管家"
netifd 网络接口管理 自动配置网口
ubus 服务间通信总线 组件间的"对讲机"

OpenWrt的特点:每个配置都有默认值,不用改源码,通过UCI覆盖即可。改WiFi密码不用编译,直接uci set wireless.@wifi-iface[0].key='password' && uci commit。


三、对比总表

三大系统核心对比

维度 Buildroot Yocto OpenWrt
开源指标 \~3.2K stars(GitLab) Yocto Project官网托管 \~23K stars
学习曲线 低 高 中
首次构建时间 10-30分钟 1-4小时 30-60分钟
配置方式 make menuconfig BitBake + Layer make menuconfig
包管理器 无(需重新编译) opkg/RPM/DEB(可选) opkg
OTA更新 不支持 支持(包级更新) 支持(sysupgrade)
适合场景 单用途设备 企业级产品 网络设备
芯片支持 主流架构 所有架构 主要MIPS/ARM
厂商支持 社区为主 NXP/Intel等官方BSP 多厂商

OTA/升级形态差异

系统 升级方式 说明
Buildroot 整包镜像升级 无OTA能力,需重新烧录整包镜像
Yocto 整包/单包/A/B分区 通过SWUpdate/Mender/RAUC实现整包、差分包、单包升级;A/B分区双镜像支持宕机回滚
OpenWrt 整包+在线安装 sysupgrade整包升级 + opkg在线安装软件,路由场景标配

A/B分区(双镜像):一块Flash分成A/B两个系统分区,升级时在备用分区写入新系统,写入成功后再切换。升级失败自动回滚到旧分区,设备永不失联。

初始化系统差异

系统 默认init 可选方案
Buildroot BusyBox init systemd、sysvinit
Yocto 可配置 systemd、sysvinit、BusyBox
OpenWrt procd(专用) 不支持其他方案

Buildroot默认使用BusyBox的init,体积小、启动快,适合资源受限设备。Yocto灵活性高,量产产品通常用systemd。OpenWrt的procd专为路由器设计,支持热插拔检测和进程守护。

选型决策流程

flowchart TB A["你的项目类型?"] --> B{"设备类型"} B -->|"路由器/网关"| C["OpenWrt<br/>专注网络,UCI开箱即用"] B -->|"工业PLC/传感器<br/>手持设备"| D{"规模?"} B -->|"智能汽车<br/>多媒体终端"| E["Yocto<br/>企业级定制"] D -->|"小批量/原型"| F["Buildroot<br/>快速出镜像"] D -->|"大批量/商业"| G["Yocto<br/>LTS支持+SDK"] style C fill:#E8F5E9,stroke:#388E3C style F fill:#E3F2FD,stroke:#1976D2 style G fill:#FFF8E1,stroke:#F57C00

四、实战步骤

Buildroot实战(以RK平台为例)

环境准备

# ===== 宿主机:安装依赖 =====
sudo apt update
sudo apt install -y build-essential git make gcc g++ \
    python3 bc unzip dosfstools mtools parted \
    libncurses-dev libssl-dev bison flex

# ===== 克隆Buildroot =====
git clone https://github.com/buildroot/buildroot.git
cd buildroot

# ===== 选择RK平台默认配置 =====
make list-defconfigs | grep -i rockchip
# 输出:rockchip_rk356x_defconfig
make rockchip_rk356x_defconfig

图形化配置

# 打开图形配置界面
make menuconfig

# 常用配置项:
# Target options → 目标架构(ARM/ARM64/RISC-V)
# Build options → 并行编译核心数
# Toolchain → 交叉工具链配置
# System configuration → 主机名/root密码/初始化系统
# Kernel → 内核版本和配置
# Target packages → 应用软件(BusyBox/Network/wifi工具等)
# Filesystem images → 输出镜像格式(ext4/squashfs/ubi)

编译和输出

# ===== 开始构建(8核并行)=====
make -j$(nproc)

# ===== 构建完成,查看产物 =====
ls output/images/
# ├── rootfs.ext4          # 根文件系统镜像
# ├── rootfs.squashfs      # 压缩只读根文件系统
# ├── rk356x-sdcard.img    # 可启动SD卡镜像
# └── u-boot.itb           # Bootloader

# ===== 常用命令 =====
make defconfig          # 恢复默认配置(从defconfig恢复)
make savedefconfig      # 保存当前配置为defconfig
make clean              # 清理构建产物
make clean-all          # 完全清理(包含工具链)

外部工具链:Buildroot支持使用外部预编译工具链(如Linaro GCC),通过Toolchain → Toolchain type → External toolchain配置,适合与芯片厂商SDK保持一致的场景。

添加自定义软件包

# ===== 创建hello软件包 ======
mkdir package/hello
cat > package/hello/Config.in << 'EOF'
config BR2_PACKAGE_HELLO
    bool "hello"
    help
        A simple hello world program
EOF

cat > package/hello/hello.mk << 'EOF'
HELLO_VERSION = 1.0
HELLO_SITE = /home/user/src
HELLO_SITE_METHOD = local
HELLO_PROGRAMS = hello
define HELLO_BUILD_CMDS
    $(MAKE) CC="$(TARGET_CC)" CFLAGS="$(TARGET_CFLAGS)" -C $(HELLO_SRCDIR)
endef
define HELLO_INSTALL_TARGET_CMDS
    $(INSTALL) -D -m 0755 $(HELLO_SRCDIR)/hello $(TARGET_DIR)/usr/bin/hello
endef
$(eval $(generic-package))
EOF

# ===== 在配置中启用 =====
make menuconfig
# 找到 Target packages → hello → 勾选

# ===== 重新编译 =====
make hello-rebuild all

Yocto实战(Poky基础)

环境准备

# ===== 宿主机:安装依赖 =====
sudo apt install -y gawk wget git-core diffstat \
    python3 gcc build-essential chrpath cpio \
    texinfo libsdl1.2-dev xterm locales

# ===== 克隆Poky(Yocto参考发行版)=====
git clone https://github.com/yoctoproject/poky.git
cd poky
git checkout dunfell  # dunfell为官方长期支持版本,生产环境优先选用

# ===== 初始化构建环境 =====
source oe-init-build-env build_qemu

# ===== 查看支持的机器 ======
ls conf/local.conf
# MACHINE ??= "qemux86-64"  # 默认QEMU虚拟机

添加Rockchip BSP层

# ===== 克隆RK BSP层 ======
cd ..
git clone https://github.com/rockchip-linux/meta-rockchip.git

# ===== 添加到构建环境 ======
source oe-init-build-env build_rk356x
bitbake-layers add-layer ../../meta-rockchip

# ===== 配置local.conf ======
cat >> conf/local.conf << 'EOF'
MACHINE = "rockchip-rk356x-64"
ACCEPT_FSL_EULA = "1"
EOF

# ===== 构建镜像 =====
bitbake core-image-minimal

# ===== 查看产物 =====
ls tmp/deploy/images/rockchip-rk356x-64/
# ├── core-image-minimal-rockchip-rk356x-64.rootfs.ext4
# ├── modules-5.10.72-rockchip-rk356x-64.ipk
# └── zImage -> vmlinuz-5.10.72-rockchip-rk356x-64.bin

首次编译速度较慢:包含源码下载、工具链编译、软件包编译,整体耗时可达数小时。启用sstate-cache(共享构建缓存)和DL_DIR(源码预下载)可大幅加速后续编译。配置方法:在local.conf中添加SSTATE_DIR = "/path/to/sstate-cache"和DL_DIR = "/path/to/downloads"。

镜像类型选择:

  • core-image-minimal:最小镜像,仅含内核和基础命令,适合裸设备启动
  • core-image-base:控制台镜像,支持目标板硬件
  • core-image-full-cmdline:完整控制台镜像,含更多工具
  • core-image-sato:含图形界面(Sato桌面),适合带屏幕设备

创建自定义Layer

# ===== 创建新Layer ======
bitbake-layers create-layer meta-myproduct
cd meta-myproduct

# ===== 查看Layer结构 =====
ls
# ├── conf/
# │   └── layer.conf          # Layer配置文件
# ├── recipes-core/
# │   └── images/              # 镜像定义
# └── recipes-example/
#     └── example/
#         └── example_1.0.bb  # Recipe文件

# ===== 编写Recipe(示例)=====
cat > recipes-example/example/example_1.0.bb << 'EOF'
SUMMARY = "Example application"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COREBASE}/LICENSE;md5=3f40d799439710da5d3cf"

SRC_URI = "git://github.com/myrepo/example.git;branch=main"
SRCREV = "${AUTOREV}"

do_compile() {
    oe_runmake
}

do_install() {
    install -d ${D}${bindir}
    install -m 0755 ${S}/example ${D}${bindir}
}
EOF

# ===== 添加到构建环境 ======
bitbake-layers add-layer ../../meta-myproduct
bitbake example

OpenWrt实战

环境准备

# ===== 克隆OpenWrt源码 ======
git clone https://github.com/openwrt/openwrt.git
cd openwrt

# ===== 选择稳定分支 ======
git checkout openwrt-23.05  # 23.05稳定版

# ===== 安装依赖 ======
./scripts/feeds update -a
./scripts/feeds install -a

# ===== 预下载源码(避免编译中断)=====
make download

feeds机制:OpenWrt的软件包不都在主线,通过feeds从第三方仓库引入。如需添加LuCI图形界面,执行./scripts/feeds install -a后可在make menuconfig → LuCI中勾选。

配置编译

# ===== 图形化配置 =====
make menuconfig

# 关键配置项:
# Target System → ARM ARMv8 (64-bit)
# Subtarget → Rockchip ARMv8
# Target Profile → Rockchip RK356x
# LuCI → Web管理界面
# Network → 网络相关(WiFi/VPN等)

# ===== 编译 ======
# V=s 表示输出完整编译日志,方便定位报错
make V=s -j1

# 或并行编译(机器够强的话)
make -j$(nproc)

UCI配置示例

# ===== 配置WiFi(通过UCI,不用改源码)=====
# 编辑 /etc/config/wireless
config wifi-device 'radio0'
    option type 'mac80211'
    option channel '36'
    option hwmode '11a'
    option htmode 'VHT80'

config wifi-iface
    option device 'radio0'
    option network 'lan'
    option mode 'ap'
    option ssid 'MyRouter'
    option encryption 'psk2'
    option key 'mypassword'

# ===== 应用配置 ======
wifi config
/etc/init.d/network restart

# ===== 通过命令行快速配置 ======
uci set wireless.radio0.channel='6'
uci set wireless.@wifi-iface[0].ssid='NewSSID'
uci commit wireless
wifi

五、常见问题解决

Buildroot常见问题

现象 根因 解决
编译报"unterminated call" Makefile语法错误 检查.mk文件的缩进,必须用Tab
提示"package xxx not found" 配置未启用 make menuconfig勾选对应包
镜像太大塞不进Flash 未优化根文件系统 启用Compression,选Minimal配置
工具链编译失败 依赖缺失 apt install build-essential

Yocto常见问题

现象 根因 解决
bitbake卡在"Waiting for 4 background tasks" 网络下载慢/sstate未命中 配置镜像源,启用sstate-cache
构建失败"do_compile failed" 交叉编译参数错误 检查TCLIBC/TARGET_ARCH
内存不足OOM 机器配置太低 8G+内存,SWAP 16G
Layer添加后报错"not a BB_CLASSDIR" layer路径错误 检查conf/bblayers.conf路径

OpenWrt常见问题

现象 根因 解决命令
WiFi搜不到 驱动未编译 make menuconfig → 勾选 mac80211
Luci管理界面打不开 uhttpd未启动 /etc/init.d/uhttpd enable && start
刷机提示空间不足 默认分区太小 修改 target/linux/xxx/image/Makefile

调试命令速查

# ===== Buildroot调试 =====
make clean                      # 清理构建
make clean-all                  # 完全清理
make savedefconfig              # 保存当前配置
make list-defconfigs            # 列出可用配置

# ===== Yocto调试 =====
bitbake -c cleanall <package>   # 清理包构建
bitbake -e <package> | head     # 查看包变量
bitbake -g <package>            # 生成依赖图
bitbake-layers show-recipes     # 显示所有recipes

# ===== OpenWrt调试 =====
./scripts/feeds update           # 更新软件源
./scripts/feeds install <pkg>   # 安装软件包
make defconfig                  # 检查配置依赖
make kernel_menuconfig          # 内核单独配置

六、总结

选型建议

场景 推荐 理由
快速原型/单用途设备 Buildroot 配置简单,十分钟出镜像
企业商业产品 Yocto LTS支持、SDK生成、包管理
路由器/网关设备 OpenWrt 专用网络功能、UCI配置
学习/练手项目 Buildroot 门槛低,问题好排查

核心口诀

Buildroot是傻瓜相机——选好配置,按下快门(make)就出片。

Yocto是专业单反——焦距、光圈、白平衡(Layer)全得自己调,但能拍电影。

OpenWrt是路由器专用工具箱——WiFi、交换机、防火墙开箱即用,不用造轮子。

构建时间参考

系统 首次构建 增量构建
Buildroot 10-30分钟 1-5分钟
Yocto 1-4小时 10-30分钟
OpenWrt 30-60分钟 5-15分钟

构建时间和机器配置强相关,高配CPU+SSD可显著加速。Yocto首次构建可通过sstate-cache加速后续编译。

生产环境避坑要点

要点 说明
版本选择 生产环境必须用LTS稳定分支,不要用开发主干。Buildroot每季度发布稳定版,Yocto每半年LTS,OpenWrt按版本代号发布
编译环境 推荐固定Ubuntu 20.04/22.04 LTS,避免新版本系统依赖兼容问题。32GB内存起步,SSD必备
源码管理 正式项目不要直接改源码。用补丁(Buildroot的*.patch)、Layer(Yocto的meta-*)、UCI配置(OpenWrt)实现定制,改源码会导致升级困难
镜像体积 文件系统类型(squashfs/ext4)、是否裁剪、是否带调试符号,体积差异极大。文中数值仅供参考,实际以你的配置为准

镜像体积参考值(仅示意):

  • Buildroot minimal(squashfs):2-10MB
  • Buildroot standard(ext4):20-50MB
  • Yocto core-image-minimal:50-150MB
  • Yocto core-image-sato(含图形):200-500MB
  • OpenWrt(基础镜像):5-15MB

版权声明

作者linuxROS
协议本作品采用 CC BY-NC-SA 4.0 许可协议:署名-非商业性使用-相同方式共享
关注欢迎关注微信公众号 linuxROS,获取更多机器人 / 嵌入式 / Linux 干货
返回首页