4. BusyBox配置详解(下):Applet选择

上一讲我们聊了配置的整体框架,这一讲咱们来点实在的——怎么精确控制Applet的开关。说白了,就是决定你的BusyBox里到底装哪些命令,扔掉哪些不需要的。

我刚开始做嵌入式项目时,总觉得功能越多越好,一股脑全编译进去。结果呢?固件体积大了好几倍,启动还慢。后来被老大骂了一顿,才学会精打细算。你想想看,嵌入式设备就那么点Flash空间,每一KB都得省着用。

4.1 Applet选择的核心思路

Applet选择,本质上就是做减法。你只需要问自己三个问题:

  • 这个命令我的系统真的需要吗?
  • 有没有其他更轻量的替代方案?
  • 去掉它会影响哪些依赖关系?

我个人习惯先列一个最小功能清单,再逐步添加。比如一个简单的嵌入式Linux系统,可能只需要:ls、cp、mv、sh、init、mount、cat、echo 这几个。其他的?嗯,先关掉再说。

核心原则:只保留你确定要用的,其他全部关掉。不要想着"万一以后用得上"——真到那时候再重新编译也不迟。

4.2 如何精确选择Applet

进入配置界面后,你会看到一大堆分类。咱们一步步来操作。

4.2.1 使用menuconfig进行选择

运行 make menuconfig 后,找到 Busybox Settings → Busybox Library Tuning → Applet selection。这里有几个关键选项:

选项 说明 我的建议
Individual applets 逐个选择每个Applet 推荐,最灵活
All applets 全部编译 不推荐,除非你空间无限
None 一个都不编译 调试用,别当真

选择 Individual applets 后,你就可以进入各个分类,手动勾选或取消勾选了。

4.2.2 实战:只保留ls、cp、mv、sh

假设我们只需要这四个命令,其他全部去掉。操作步骤如下:

  1. 进入 Coreutils 分类,找到 ls、cp、mv,勾选为 [*]。
  2. 进入 Shells 分类,找到 sh,勾选为 [*]。
  3. 其他所有分类,比如 Networking、Login/Password Management、Linux System Utilities 等,全部保持默认(即未勾选状态)。

这里有个坑:sh 依赖 init 吗?不一定。但如果你想让系统能正常启动,至少需要 init 和 mount。我曾经在一个项目里只保留了 sh,结果系统启动后直接panic——因为没有 init 来执行启动脚本。

注意:去掉 httpd、telnetd 等网络服务时,要确认你的系统确实不需要远程管理功能。否则设备部署到现场后,想远程调试就麻烦了。

4.3 去掉不需要的命令:httpd、telnetd 等

很多嵌入式设备根本不需要Web服务器或Telnet服务。去掉它们很简单:

  • 进入 Networking 分类
  • 找到 httpd,确保是 [ ](未选中)
  • 找到 telnetd,同样取消勾选
  • 顺便检查一下 ftpd、tftpd、dhcpd 等,不需要的一并去掉

你想想看,一个传感器节点,就采集个温度数据,要什么httpd?纯属浪费空间。去掉这些网络服务,能省下几十KB到几百KB不等,具体看功能复杂度。

小技巧:在menuconfig里按 / 键可以搜索Applet名称。比如输入 httpd,它会直接跳转到对应位置,省得你一个个翻。

4.4 依赖关系与冲突处理

有些Applet之间有依赖关系。比如 login 需要 getty,mount 需要 losetup 等。如果你只选了 sh 但没选 init,编译时可能会报错。

怎么处理?我的经验是:

  1. 先选你确定需要的核心命令
  2. 尝试编译,看报错信息
  3. 根据报错补充缺失的依赖

举个例子,我曾在裁剪时只保留了 sh 和 ls,结果编译报错说 sh 需要 glob 支持。嗯,那就得把 glob 相关的选项也打开。

4.5 使用defconfig快速裁剪

如果你不想手动一个个点,可以用 make defconfig 生成默认配置,然后手动修改。我个人习惯这样:

# 生成默认配置
make defconfig

# 备份一份
cp .config .config.full

# 用脚本或手动去掉不需要的Applet
# 比如去掉所有网络相关
sed -i 's/CONFIG_HTTPD=y/# CONFIG_HTTPD is not set/' .config
sed -i 's/CONFIG_TELNETD=y/# CONFIG_TELNETD is not set/' .config

# 然后运行menuconfig微调
make menuconfig

这样效率高很多。但要注意,sed 替换时要小心,别把其他依赖也误删了。

4.6 验证裁剪结果

编译完成后,用 busybox --list 查看实际包含的命令:

# 假设你只保留了ls、cp、mv、sh
./busybox --list
# 输出应该只有这四个命令

如果多了其他命令,说明你漏关了。回去检查配置,重新编译。

验证方法:还可以用 size 命令查看BusyBox的二进制大小。裁剪前可能是1MB,裁剪后可能只有200KB。这个对比很直观。

4.7 常见问题与避坑指南

  • 问题:编译后某些命令无法使用。
    解决:检查是否缺少依赖的库或内核特性。比如 mount 需要内核支持 loop 设备。
  • 问题:系统启动后找不到 sh。
    解决:确认 sh 的路径是否正确,或者是否被 init 正确调用。
  • 问题:裁剪后固件体积没怎么减小。
    解决:检查是否还有大量未使用的Applet被编译进去。用 busybox --list 逐一核对。

我曾经在一个项目里,明明只选了10个命令,编译出来却有500KB。查了半天,发现是 CONFIG_FEATURE_* 选项开了太多,导致很多通用代码被链接进去了。所以,不仅要关Applet,还要关掉对应的特性选项。

4.8 本章小结

Applet选择是BusyBox裁剪的核心。记住:

  • 只保留你确定需要的命令
  • 注意依赖关系,缺什么补什么
  • 用 busybox --list 验证结果
  • 不要忽略特性选项对体积的影响

下一讲我们会聊更高级的裁剪技巧——如何通过配置选项进一步压缩体积。嗯,到时候见。

Applet选择核心流程 1. 需求分析 列出最小功能清单 2. 配置选择 menuconfig逐个勾选 3. 编译 make 4. 验证 busybox --list 符合 预期? 是 完成裁剪 否,返回调整 常见Applet分类 Coreutils (ls, cp, mv) Shells (sh, ash, bash) Networking (httpd, telnetd) Login (login, passwd) Linux System (mount, init) 保留 去掉 按需

本章核心:Applet选择就是做减法。先列清单,再逐个勾选,最后验证。别贪多,够用就行。

可可精品资料库