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
假设我们只需要这四个命令,其他全部去掉。操作步骤如下:
- 进入 Coreutils 分类,找到
ls、cp、mv,勾选为[*]。 - 进入 Shells 分类,找到
sh,勾选为[*]。 - 其他所有分类,比如 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,编译时可能会报错。
怎么处理?我的经验是:
- 先选你确定需要的核心命令
- 尝试编译,看报错信息
- 根据报错补充缺失的依赖
举个例子,我曾在裁剪时只保留了 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选择就是做减法。先列清单,再逐个勾选,最后验证。别贪多,够用就行。