4、BusyBox编译与安装:make与make install,生成_install目录,分析生成的文件结构
好,咱们接着往下走。上一节我们把BusyBox的配置菜单给捋了一遍,你大概知道该勾什么、不该勾什么了。那配置完了,接下来就是真刀真枪地编译和安装了。
说实话,我第一次编译BusyBox的时候,心里还挺没底的。那时候刚接触嵌入式,总觉得「make」一下就能出个文件系统,哪有这么简单?结果还真就这么简单。不过,简单归简单,里面的门道可不少。我今天就把我踩过的坑、积累的经验,一股脑倒给你。
4.1 编译:make 命令的两种用法
配置完成后,执行 make 就能开始编译。但这里有个小细节——你得先确认你的交叉编译工具链已经设置好了。
CROSS_COMPILE 环境变量。我见过太多人直接敲 make,结果编译出一堆x86的二进制文件,放到板子上直接Segmentation fault。
我个人习惯这样编译:
make CROSS_COMPILE=arm-linux-gnueabihf- -j4
解释一下:
CROSS_COMPILE:指定交叉编译工具链的前缀。比如你的工具链叫arm-linux-gnueabihf-gcc,那前缀就是arm-linux-gnueabihf-。-j4:并行编译,4个任务同时跑。这个数字一般设为你CPU核心数的1.5到2倍。我笔记本是4核8线程,通常用-j6或-j8。
如果你不想每次敲命令都带 CROSS_COMPILE,也可以在Makefile里直接写死。但我建议你别这么干——万一你换个平台,改起来麻烦。
编译过程大概持续一两分钟。你会看到屏幕上刷刷地滚过一堆编译信息。如果一切顺利,最后会生成一个 busybox 可执行文件。你可以用 file 命令看看它是不是ARM架构的:
file busybox
busybox: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 3.2.0, stripped
看到「ARM」字样,心里就踏实了。
4.2 安装:make install 干了什么?
编译完 busybox 可执行文件,下一步就是安装。注意,这里的「安装」不是装到你的PC系统里,而是生成一个根文件系统的骨架。
执行:
make install CONFIG_PREFIX=./_install
CONFIG_PREFIX 指定安装的目标目录。如果不指定,默认就是当前目录下的 _install。我个人习惯显式指定,避免搞混。
安装过程很快,几秒钟就完事。然后你会看到一个 _install 目录被创建出来。这个目录,就是咱们根文件系统的雏形。
CONFIG_STATIC),那 busybox 二进制文件会大一些,但好处是不需要额外的动态库。我在做最小系统时,特别喜欢用静态编译,省去一堆库文件的麻烦。
4.3 分析 _install 目录的文件结构
好,现在咱们来看看这个 _install 目录里到底有什么。用 tree 命令看一下:
tree -L 2 _install/
_install/
├── bin
│ ├── busybox
│ ├── cat
│ ├── chmod
│ ├── cp
│ ├── date
│ ├── echo
│ ├── grep
│ ├── kill
│ ├── ln
│ ├── ls
│ ├── mkdir
│ ├── mount
│ ├── mv
│ ├── ps
│ ├── rm
│ ├── sh
│ ├── sleep
│ ├── sync
│ ├── tar
│ ├── touch
│ └── ... (还有很多)
├── sbin
│ ├── halt
│ ├── init
│ ├── insmod
│ ├── reboot
│ ├── swapon
│ └── ...
├── usr
│ ├── bin
│ │ ├── [
│ │ ├── awk
│ │ ├── cut
│ │ ├── find
│ │ ├── head
│ │ ├── tail
│ │ ├── test
│ │ ├── wc
│ │ └── ...
│ └── sbin
│ ├── chroot
│ ├── telnetd
│ ├── udhcpc
│ └── ...
└── linuxrc -> bin/busybox
嗯,结构很清晰。我来逐个分析一下:
4.3.1 bin/ 目录
这是最核心的目录。里面放着最基本的用户命令。注意看,这些命令其实都是指向 busybox 的符号链接。不信你试试:
ls -l _install/bin/ls
lrwxrwxrwx 1 root root 14 Mar 15 10:00 _install/bin/ls -> /bin/busybox
看到了吧?ls 其实是个软链接,指向 /bin/busybox。当你执行 ls 时,实际执行的是 busybox,然后 busybox 根据 argv[0] 来判断你要执行哪个命令。
这种设计有什么好处?说白了就是省空间。一个 busybox 二进制文件包含了上百个命令,比每个命令单独一个文件省下好几MB。对于只有几MB Flash的嵌入式设备来说,这太重要了。
4.3.2 sbin/ 目录
这个目录放的是系统管理命令。比如 init、halt、reboot 这些。注意,init 是系统启动的第一个用户进程,它的作用可大了。我后面会专门讲 init 进程的启动流程。
4.3.3 usr/ 目录
这个目录下又分了 bin 和 sbin。按照传统的Unix文件系统层次结构,/usr 是放用户程序和数据的地方。但在BusyBox里,它其实也是符号链接到 busybox 的。
你可能会问:为什么要把命令分散到 bin、sbin、usr/bin、usr/sbin 这么多目录?
嗯,这其实是历史遗留问题。早期Unix系统,/bin 放的是系统启动时必须的命令,/sbin 放的是系统管理命令,/usr/bin 放的是用户安装的应用程序。虽然现在界限没那么严格了,但BusyBox还是保留了这种结构,为了兼容性。
4.3.4 linuxrc 文件
这个文件比较特殊。它是一个指向 bin/busybox 的符号链接。在嵌入式系统中,linuxrc 通常作为init进程的替代品,用于早期系统初始化。我见过有些系统直接用 linuxrc 来挂载根文件系统,然后才启动真正的 init。
4.4 文件结构背后的设计思想
咱们来总结一下。BusyBox的安装过程,本质上就是:
- 编译出一个
busybox可执行文件 - 在
_install目录下创建bin/、sbin/、usr/等目录 - 为每个启用的命令创建指向
busybox的符号链接
这种「一个二进制文件干所有事」的设计,我特别喜欢。它让根文件系统变得极其精简。你想想看,一个完整的Linux系统,光 /bin 和 /sbin 里的命令加起来就有上百个,每个都是独立的二进制文件,加起来怎么也得几十MB。而BusyBox把所有命令打包成一个文件,才几百KB。
我曾经在一个只有4MB Flash的板子上做项目。用完整的GNU工具链,根文件系统塞都塞不进去。换成BusyBox后,不仅塞进去了,还留了1MB多的空间给应用程序。这就是BusyBox的魅力。
4.5 避坑指南
- 符号链接路径问题: 如果你在
make install时指定了CONFIG_PREFIX为绝对路径,那生成的符号链接也是绝对路径。但如果你把_install目录打包后放到板子上,路径可能就不对了。我建议用相对路径,或者安装后手动检查一下链接。 - 缺少动态库: 如果你用的是动态编译,别忘了把
busybox依赖的libc.so、ld-linux.so等库文件也复制到根文件系统的/lib目录下。否则板子启动时会报No such file or directory。 - 权限问题:
busybox可执行文件需要有可执行权限。默认情况下make install会设置好,但如果你手动复制,别忘了chmod +x。
4.6 本章小结
好了,这一章的内容就这些。我们完成了BusyBox的编译和安装,生成了 _install 目录,并分析了它的文件结构。你现在应该能回答这几个问题了:
make和make install分别干了什么?_install目录下有哪些子目录?每个目录的作用是什么?- 为什么
ls、cat这些命令都是符号链接? linuxrc文件是干什么用的?
下一章,我们会把这个 _install 目录变成一个真正能启动的根文件系统。到时候,咱们要添加设备节点、配置文件、初始化脚本……嗯,内容不少,但每一步都很有意思。
可可精品资料库