BusyBox 中文文档 下载 App

BusyBox 静态编译与动态链接怎么选

两种编译方式

BusyBox 可以编译成静态二进制也可以编译成动态二进制,在 menuconfig 的 Build Options 里控制:

Build Options  --->
    [*] Build BusyBox as a static binary (no shared libs)
方式产物体积依赖适合场景
静态编译~1.1MB(musl)无嵌入式设备、initramfs、Docker 极简镜像
动态编译~700KB需要目标系统有完整 libc目标系统已有 GNU libc 时省空间

为什么嵌入式场景选静态

绝大多数嵌入式设备的根文件系统非常精简,通常没有完整的动态链接器和 libc.so。如果 BusyBox 是动态链接的,目标设备上必须同时部署:

这些加起来又是几百 KB 到 1MB——比静态编译 BusyBox 本身还大。静态编译虽然 BusyBox 多了 300KB,但总磁盘占用反而更小(省掉了 libc.so)。

musl vs glibc

如果静态编译,用哪个 libc 决定了最终体积:

BusyBox 1.36.1 defconfig 静态编译体积对比:
  musl libc:   1,084,312 bytes (~1.03 MB)
  glibc:       1,327,648 bytes (~1.27 MB)
  dietlibc:      ? KB(更小但功能严重不足,不推荐生产)

musl 体积优势源于它本身就是为嵌入式和静态链接设计的最小 C 库,去掉了 glibc 中大量为了兼容性而保留的冗余实现。musl 在嵌入式和容器生态中已成为主流——Alpine Linux、OpenWrt(默认)、Buildroot(默认)都基于 musl。

但 musl 和 glibc 有一些行为差异,极少数依赖 glibc 特定行为的工具在 musl 上可能出错。BusyBox 本身用 musl 编译完全没问题,但如果你的应用也静态链接 musl,记得测一遍实际行为。

交叉编译

BusyBox 设计时就考虑了交叉编译,menuconfig 里 Build Options → Cross compiler prefix 填上交叉编译器前缀即可:

# 示例:为 ARM Cortex-A 编译
make defconfig
make menuconfig   # 在 Build Options 里填 Cross compiler prefix = arm-linux-gnueabihf-
make -j$(nproc)

# 或者直接命令行指定(跳过 menuconfig)
make defconfig
make CROSS_COMPILE=arm-linux-gnueabihf- -j$(nproc)

Buildroot 和 OpenWrt 会自动处理交叉编译工具链和 prefix,不需要手动填。

strip 不可少

编译出来的二进制必须 strip——BusyBox 的 Makefile 默认会 strip,但如果你是手动编译或者不想破坏某些调试配置,可以显式执行:

make   # 默认会 strip
# 如果关闭了自动 strip:
strip --strip-all busybox
# 额外优化:
strip -s busybox   # 与 --strip-all 类似

strip 能砍掉 30-50% 的体积,去掉调试符号和冗余段。嵌入式部署前务必执行。

LTO 优化

CONFIG_LTO=y 开启链接时优化。编译器会跨文件内联函数、消除死代码、合并重复逻辑,通常能再减 5-15% 体积。代价是编译时间变长(大约慢 2-3 倍),需要较新的 GCC(>= 4.8)或 Clang。

嵌入式项目如果体积紧张就开 LTO,如果编译时间敏感(CI 环境)可以关。