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 版本对不对这类问题。
编译过程
下载源码
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.0busybox.net 在国内访问不太稳定,第一次连接可能超时,wget 会自动重试。
生成默认配置
make defconfig开启静态编译
有两种方式。图形化方式需要进 make menuconfig(需要 ncurses 库和支持 TUI 的终端):
Settings --->
[*] Build static binary (no shared libs)或者直接用命令行一行搞定:
sed -i 's/# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config验证:
grep CONFIG_STATIC .configCONFIG_STATIC=y
CONFIG_STATIC_LIBGCC=y禁用 tc
BusyBox 1.37.0 的 tc(traffic control)模块和新版内核头文件不兼容,静态编译会报一堆 struct tc_cbq_wrropt 未定义的错误。这是已知问题,Medium 上 2026 年 2 月的教程也提到了需要禁用 tc。
sed -i 's/CONFIG_TC=y/CONFIG_TC=n/' .configtc 是流量控制工具,迷你系统用不上。
编译
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 解析),其他的被排除了。这就是静态编译的好处之一:只包含实际用到的代码。
安装
make install安装目录由 .config 里的 CONFIG_PREFIX 决定,默认是 ./_install。make install 做的事情:
- 把
busybox二进制复制到_install/bin/busybox - 根据编译时启用的命令,创建符号链接(
ls → busybox、cat → busybox……) - 创建
linuxrc → bin/busybox
也可以通过命令行覆盖安装路径:
make install CONFIG_PREFIX=/your/custom/path验证
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。
ls -lh _install/bin/busybox-rwxr-xr-x 1 hceax hceax 2.4M Mar 27 21:30 _install/bin/busybox2.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 就能跑。
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 提供了命令工具,但还差三样东西:
/init脚本——内核启动后运行的第一个程序/proc、/sys、/dev目录——虚拟文件系统的挂载点- initramfs 打包——把整个目录压缩成内核能识别的 cpio.gz 格式
下一篇把这些串起来,在 QEMU 里跑出一个完整的最小 Linux 系统。