第二章 嵌入式Linux系统搭建:交叉编译环境配置、根文件系统制作、内核编译与烧录
好,咱们直接进入正题。这一章要搞定的,是嵌入式Linux开发最基础、也最绕不开的一步——搭建系统环境。
说实话,我见过太多新手在这一步卡壳。明明代码写得挺好,一交叉编译就报错,一烧录就起不来。嗯,别急,咱们一步步来。
2.1 交叉编译环境配置
先问个问题:为什么要在PC上交叉编译?
你想想看,智能音箱的芯片,通常是ARM架构的。它跑不了x86的二进制文件。而我们的开发机是x86的。所以,得在x86上编译出ARM能跑的程序。这就是交叉编译。
我个人习惯用Linaro提供的工具链。稳定,社区支持也好。
核心思路: 在PC上安装ARM交叉编译器,编译出的程序才能在音箱上运行。
2.1.1 下载与安装交叉编译器
我推荐gcc-arm-linux-gnueabihf这个版本。它支持硬浮点,对音频处理这类计算密集型任务特别友好。
# 下载工具链
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
# 解压到指定目录
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/
# 配置环境变量
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
这里有个坑。我曾经直接把工具链解压到/usr/local下,结果跟系统自带的gcc冲突了。后来我学乖了,统一放到/opt下,用环境变量隔离。
小技巧: 把export命令写到~/.bashrc里,这样每次打开终端就不用重新设了。
2.1.2 验证工具链
装好了,得试试能不能用。
arm-linux-gnueabihf-gcc --version
如果看到版本号,恭喜你,第一步走通了。
再写个简单的hello world测试一下:
# 写个测试文件
echo '#include <stdio.h>
int main() {
printf("Hello, Smart Speaker!\n");
return 0;
}' > test.c
# 交叉编译
arm-linux-gnueabihf-gcc -o test test.c
# 查看文件信息
file test
输出应该是:test: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)。看到ARM字样,说明编译出来的确实是ARM架构的程序。
2.2 根文件系统制作
根文件系统,说白了就是Linux启动后挂载的第一个文件系统。它包含了系统运行所需的所有库、工具和配置文件。
我刚开始做的时候,总以为根文件系统就是一堆文件夹。后来发现,少了任何一个关键库,系统都起不来。
2.2.1 使用BusyBox构建最小根文件系统
BusyBox是个好东西。它把几百个Linux命令打包成一个可执行文件,特别适合嵌入式系统。
# 下载BusyBox
wget https://busybox.net/downloads/busybox-1.36.0.tar.bz2
tar -xvf busybox-1.36.0.tar.bz2
cd busybox-1.36.0
# 配置
make menuconfig
# 关键配置项:
# 1. 选择静态编译:Settings -> Build static binary (no shared libs)
# 2. 设置交叉编译器前缀:Settings -> Cross compiler prefix = arm-linux-gnueabihf-
# 3. 安装路径:Settings -> Destination path for 'make install' = ../rootfs
注意: 静态编译会让BusyBox体积变大,但好处是不依赖动态库。对于智能音箱这种存储有限的设备,我建议用动态编译,但要确保所有依赖库都拷贝到根文件系统里。
配置完,编译安装:
make -j4
make install
安装完成后,会在../rootfs目录下生成基本的文件系统结构:bin、sbin、usr、etc等目录。
2.2.2 添加必要的库和配置文件
光有BusyBox还不够。系统启动还需要一些关键文件。
我记得有一次,烧录完系统死活起不来,最后发现是缺少了/dev/console设备节点。这种低级错误,犯过一次就记住了。
手动创建必要的目录和设备节点:
cd ../rootfs
mkdir -p dev proc sys tmp var/log etc/init.d
# 创建设备节点
sudo mknod dev/console c 5 1
sudo mknod dev/null c 1 3
创建初始化脚本etc/inittab:
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
创建etc/init.d/rcS:
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t tmpfs none /tmp
echo "Welcome to Smart Speaker Linux!"
/bin/sh
别忘了给执行权限:
chmod +x etc/init.d/rcS
2.2.3 添加音频相关库
智能音箱嘛,音频处理是核心。我们需要把ALSA(Advanced Linux Sound Architecture)库加进去。
从交叉编译好的ALSA库中拷贝相关文件:
# 假设ALSA库安装在/opt/alsa-lib-arm目录
cp -r /opt/alsa-lib-arm/lib/* rootfs/lib/
cp -r /opt/alsa-lib-arm/include/* rootfs/usr/include/
经验之谈: 音频库的版本一定要跟内核驱动匹配。我曾经因为ALSA库版本不对,导致录音全是噪音。折腾了两天才发现是库和驱动不兼容。
2.3 内核编译与烧录
内核是系统的核心。智能音箱的内核,需要针对音频处理、网络连接做专门优化。
2.3.1 获取内核源码
我一般用Linux内核的LTS版本,稳定。对于智能音箱,4.19或5.10都是不错的选择。
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.200.tar.xz
tar -xvf linux-5.10.200.tar.xz
cd linux-5.10.200
2.3.2 配置内核
配置内核,说白了就是告诉内核:我需要哪些功能,不需要哪些功能。
# 设置交叉编译环境
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
# 使用默认配置
make vexpress_defconfig
# 自定义配置
make menuconfig
在menuconfig中,有几个关键选项必须打开:
| 配置项 | 路径 | 说明 |
|---|---|---|
| ALSA | Device Drivers -> Sound card support -> ALSA | 音频支持,必须 |
| I2S | Device Drivers -> Sound card support -> ALSA for SoC audio | 音频接口,智能音箱常用 |
| WiFi | Networking support -> Wireless | 网络连接,必须 |
| USB | Device Drivers -> USB support | 外设连接 |
重点: 不要一股脑把所有驱动都编译进去。每多一个驱动,内核体积就大一分,启动时间就长一秒。智能音箱讲究的是快速启动,能省则省。
2.3.3 编译内核
# 编译内核镜像
make -j4 zImage
# 编译设备树
make -j4 dtbs
# 编译内核模块
make -j4 modules
# 安装内核模块到根文件系统
make modules_install INSTALL_MOD_PATH=../rootfs
编译完成后,会在arch/arm/boot/目录下生成zImage文件。这就是我们要烧录的内核镜像。
2.3.4 烧录到开发板
烧录方式取决于你的开发板。我以常见的SD卡启动为例。
# 假设SD卡设备是/dev/sdb
sudo dd if=arch/arm/boot/zImage of=/dev/sdb bs=1M seek=1
sudo dd if=arch/arm/boot/dts/vexpress-v2p-ca9.dtb of=/dev/sdb bs=1M seek=5
# 将根文件系统拷贝到SD卡第二个分区
sudo mount /dev/sdb2 /mnt
sudo cp -r ../rootfs/* /mnt/
sudo umount /mnt
警告: 烧录前一定要确认SD卡设备号。我见过有人把/dev/sda(系统盘)当成SD卡来烧,结果电脑系统直接挂了。血的教训。
2.4 启动验证
烧录完,插上SD卡,上电。如果一切顺利,你会看到串口输出类似这样的信息:
Starting kernel ...
Booting Linux on physical CPU 0x0
Linux version 5.10.200 (user@host) (arm-linux-gnueabihf-gcc)
...
VFS: Mounted root (ext2 filesystem) on device 179:2.
Freeing unused kernel memory: 1024K
Welcome to Smart Speaker Linux!
/ #
看到这个提示符,说明系统跑起来了。
输入ls /dev,看看音频设备有没有识别到:
/ # ls /dev/snd/
controlC0 pcmC0D0c pcmC0D0p timer
有pcmC0D0c(录音设备)和pcmC0D0p(播放设备),说明音频驱动加载成功了。
最后说一句: 嵌入式Linux搭建,说白了就是三板斧:交叉编译、根文件系统、内核。这三步走通了,后面部署深度学习模型才有基础。别急,慢慢来,每一步都验证通过再往下走。
下一章,咱们开始搞深度学习模型的交叉编译和部署。到时候你会发现,系统搭好了,后面的事情就顺了。