Skip to content

BusyBox 静态编译:用 2.4 MB 撑起一个 Linux

上一篇编译了一个 14 MB 的 defconfig 内核。但内核本身只是一个"管理者"——管理 CPU、内存、设备,提供系统调用接口。它不包含任何用户能直接使用的东西:没有 shell、没有 ls、没有 cat。这些全部存在于根文件系统(rootfs)里。

BusyBox 就是解决这个问题的工具——一个 2.4 MB 的静态二进制,提供 300 多个 Linux 命令。

为什么选 BusyBox

正常的 Linux 发行版里,ls 来自 coreutils,bash 是单独的包,mount 来自 util-linux……每个工具都是独立的二进制,加上它们依赖的共享库(glibc、libselinux、libcap……),一个最小的 Ubuntu 根文件系统也要几百 MB。

BusyBox 的思路完全不同。它把 300 多个命令的实现全部编译到一个二进制文件里,然后通过符号链接来区分调用的是哪个命令:

/bin/ls      → /bin/busybox
/bin/cat     → /bin/busybox
/bin/sh      → /bin/busybox
/sbin/mount  → /bin/busybox

运行 /bin/ls 时,实际执行的是 busybox。BusyBox 通过 argv[0](进程名)判断你调用的是哪个命令,然后运行对应的功能。一个二进制搞定一切。

静态编译 vs 动态编译

网上有些教程建议动态编译 BusyBox——这在嵌入式开发板 + SD 卡 rootfs 的场景下是合理的(rootfs 上还要跑其他动态链接的程序,共享库可以复用)。但对 QEMU + initramfs 方案,静态编译是更好的选择:

静态编译动态编译
依赖无,自包含需要拷贝 libc、ld-linux 等共享库
部署扔一个文件就行还要确保库版本匹配、路径正确
initramfs 大小~1.3 MB(只有 busybox)~30+ MB(busybox + 库文件)
其他程序各自静态编译即可可以共享库

静态编译后的 BusyBox 不依赖任何外部文件,放进 initramfs 就能跑。不需要操心 ld-linux-x86-64.so.2 在不在、libc.so.6 版本对不对这类问题。

编译过程

下载源码

bash
cd ~/build
wget https://busybox.net/downloads/busybox-1.37.0.tar.bz2
tar -xjf busybox-1.37.0.tar.bz2
cd busybox-1.37.0

busybox.net 在国内访问不太稳定,第一次连接可能超时,wget 会自动重试。

生成默认配置

bash
make defconfig

开启静态编译

有两种方式。图形化方式需要进 make menuconfig(需要 ncurses 库和支持 TUI 的终端):

Settings  --->
    [*] Build static binary (no shared libs)

或者直接用命令行一行搞定:

bash
sed -i 's/# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config

验证:

bash
grep CONFIG_STATIC .config
CONFIG_STATIC=y
CONFIG_STATIC_LIBGCC=y

禁用 tc

BusyBox 1.37.0 的 tc(traffic control)模块和新版内核头文件不兼容,静态编译会报一堆 struct tc_cbq_wrropt 未定义的错误。这是已知问题,Medium 上 2026 年 2 月的教程也提到了需要禁用 tc。

bash
sed -i 's/CONFIG_TC=y/CONFIG_TC=n/' .config

tc 是流量控制工具,迷你系统用不上。

编译

bash
make -j$(nproc)

32 核大概几秒就编译完了。末尾输出:

  LINK    busybox_unstripped
Static linking against glibc, can't use --gc-sections
Trying libraries: crypt m resolv rt
 Library crypt is not needed, excluding it
 Library m is needed, can't exclude it (yet)
 Library resolv is needed, can't exclude it (yet)
 Library rt is not needed, excluding it
Final link with: m resolv

链接器自动检测了哪些库是真正需要的——最终只链接了 libm(数学库)和 libresolv(DNS 解析),其他的被排除了。这就是静态编译的好处之一:只包含实际用到的代码。

安装

bash
make install

安装目录由 .config 里的 CONFIG_PREFIX 决定,默认是 ./_installmake install 做的事情:

  1. busybox 二进制复制到 _install/bin/busybox
  2. 根据编译时启用的命令,创建符号链接(ls → busyboxcat → busybox……)
  3. 创建 linuxrc → bin/busybox

也可以通过命令行覆盖安装路径:

bash
make install CONFIG_PREFIX=/your/custom/path

验证

bash
file _install/bin/busybox
_install/bin/busybox: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux),
statically linked, BuildID[sha1]=9088a36b..., for GNU/Linux 3.2.0, stripped

关键词:statically linked

bash
ls -lh _install/bin/busybox
-rwxr-xr-x 1 hceax hceax 2.4M Mar 27 21:30 _install/bin/busybox

2.4 MB,包含 300+ 个 Linux 命令。

安装后的目录结构

_install/
├── bin/
│   ├── busybox       ← 唯一的真实二进制(2.4 MB)
│   ├── ls → busybox  ← 符号链接
│   ├── cat → busybox
│   ├── sh → busybox
│   ├── mount → busybox
│   └── ... (200+ 个链接)
├── sbin/
│   ├── init → ../bin/busybox
│   ├── reboot → ../bin/busybox
│   └── ...
├── usr/
│   ├── bin/
│   └── sbin/
└── linuxrc → bin/busybox

注意这里没有 /init 文件、没有 /proc/sys/dev 目录。这些需要我们手动创建——这就是下一篇"QEMU 最小系统实战"要做的事。

其他程序怎么办

BusyBox 静态编译不影响在同一个 rootfs 里运行其他程序。如果要加自己的程序:

简单程序:也用 gcc -static 静态编译,扔进 initramfs 就能跑。

bash
gcc -static -o hello hello.c
cp hello ~/build/busybox-1.37.0/_install/usr/bin/

复杂应用(如 GCC):静态编译不现实(GCC 依赖链太深),需要换方案——磁盘镜像代替 initramfs,或者用 9p/virtfs 共享宿主机目录,或者直接上 Alpine Linux / Buildroot。

但对于学习和实验来说,BusyBox + 几个静态编译的小程序完全够用。

下一步

BusyBox 提供了命令工具,但还差三样东西:

  1. /init 脚本——内核启动后运行的第一个程序
  2. /proc/sys/dev 目录——虚拟文件系统的挂载点
  3. initramfs 打包——把整个目录压缩成内核能识别的 cpio.gz 格式

下一篇把这些串起来,在 QEMU 里跑出一个完整的最小 Linux 系统。

最后更新于:

Hosted by GitHub Pages