3. 嵌入式Linux系统构建:交叉编译环境搭建、U-Boot移植与配置、Linux内核裁剪与编译、根文件系统制作
嵌入式Linux系统构建,说白了就是给硬件“装脑子”。我见过不少工程师,拿到一块新板子就急着写应用,结果底层一跑就崩。嗯,这章咱们就把这套流程捋清楚。
核心流程:交叉编译工具链 → Bootloader(U-Boot)→ Linux内核 → 根文件系统(Rootfs)。这四步走完,你的板子才算真正“活”了。
3.1 交叉编译环境搭建
交叉编译,就是在一台高性能PC(x86)上,编译出能在ARM板子上跑的程序。你想想看,板子那点算力,编译个内核得等到猴年马月?
我个人习惯用Linaro GCC,稳定且社区活跃。当然,你也可以用Buildroot或Yocto自带的工具链,但新手我建议先手动搭一遍,理解原理。
我的经验:工具链版本一定要和内核匹配。我曾经用gcc 9.x编译Linux 4.19的内核,结果莫名奇妙报__builtin_bswap16错误,折腾了两天。后来换成gcc 8.3,一次过。
搭建步骤
- 下载工具链:从Linaro官网或ARM官网下载预编译包。例如:
gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz - 解压到指定目录:
tar -xvf gcc-linaro-*.tar.xz -C /opt/toolchains/ - 设置环境变量:编辑
~/.bashrc,添加:
export PATH=/opt/toolchains/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
- 验证:运行
arm-linux-gnueabihf-gcc --version,看到版本信息就对了。
注意:环境变量ARCH和CROSS_COMPILE是内核编译的“通行证”。忘了设?内核默认走x86编译,烧到ARM板上直接黑屏。
3.2 U-Boot移植与配置
U-Boot是板子的“第一口奶”。上电后,CPU先跑U-Boot,初始化DDR、时钟、串口,然后引导内核。我遇到过最坑的事——U-Boot串口没配好,板子跑起来完全没输出,还以为变砖了。
移植要点
| 步骤 | 操作 | 常见坑 |
|---|---|---|
| 1. 获取源码 | 从denx.de或芯片厂商(NXP/ST/Allwinner)获取 |
版本太老,不支持新DDR颗粒 |
| 2. 选择参考板 | 找最接近的官方开发板配置,如mx6ull_14x14_evk_defconfig |
直接拿过来改,比从零配快10倍 |
| 3. 修改设备树 | 调整DDR参数、GPIO复用、网口PHY地址 | DDR时序配错,板子直接挂死在初始化 |
| 4. 编译 | make <board>_defconfig && make -j4 |
记得先make distclean,避免残留配置 |
| 5. 烧录验证 | 通过SD卡或JTAG烧录,串口看启动log | 波特率设错?115200是标准,别用9600 |
核心命令:U-Boot启动后,用printenv查看环境变量,setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk0p2'设置内核启动参数。我习惯把常用命令写成脚本,省得每次敲。
3.3 Linux内核裁剪与编译
内核裁剪,说白了就是“减负”。工业网关不需要蓝牙、Wi-Fi、游戏手柄驱动,全编译进去不仅占空间,还拖慢启动速度。我做过一个项目,裁剪后内核从8MB缩到2.3MB,启动时间从12秒降到4秒。
裁剪流程
- 获取内核源码:从
kernel.org或芯片厂商BSP包获取。 - 配置内核:运行
make menuconfig,进入图形界面。 - 关键裁剪项:
- 关闭无用架构支持(只保留ARM)
- 关闭无用驱动(蓝牙、Wi-Fi、USB Gadget等)
- 保留必要驱动(串口、网卡、GPIO、I2C、SPI、看门狗)
- 文件系统支持:ext4、squashfs(只读根文件系统用)
- 编译:
make zImage -j4(ARM架构生成zImage) - 编译设备树:
make dtbs
# 我的常用裁剪命令组合
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- <board>_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
# 保存配置后
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage dtbs -j4
避坑指南:我曾经裁剪时把CONFIG_DEVTMPFS关了,结果根文件系统挂载后/dev目录是空的,所有设备都找不到。嗯,这个选项必须开。
3.4 根文件系统制作
根文件系统是用户空间的“家”。没有它,内核启动后只能干瞪眼。工业场景我推荐两种方案:
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Buildroot | 中小型项目,快速原型 | 配置简单,编译快,镜像小 | 包管理弱,扩展性一般 |
| Yocto | 大型项目,产品级定制 | 高度可定制,包管理强,层机制灵活 | 学习曲线陡,编译慢(第一次可能要6小时) |
Buildroot快速上手
- 下载:
git clone git://git.buildroot.net/buildroot - 配置:
make menuconfig,选择目标架构(ARM)、工具链(外部工具链)、包(busybox、dropbear SSH、ntp等) - 编译:
make -j4,输出在output/images/目录 - 生成镜像:rootfs.tar、rootfs.cpio、rootfs.ext4等格式可选
注意:Buildroot默认用glibc,如果你板子Flash小(<64MB),建议换uclibc或musl,能省30%空间。我有个项目用musl,根文件系统最终只有4.2MB。
Yocto核心概念
- Layer(层):meta层、meta-yocto-bsp层、meta-
层 - Recipe(配方):描述如何下载、配置、编译、安装一个包
- BitBake:构建引擎,类似make的升级版
# Yocto常用命令
source oe-init-build-env
bitbake core-image-minimal # 最小系统
bitbake core-image-full-cmdline # 完整命令行系统
我的建议:新手先用Buildroot跑通流程,理解根文件系统结构(/bin、/sbin、/etc、/lib、/usr等)。等需要定制systemd服务、多用户权限、OTA升级时,再上Yocto。别一上来就搞Yocto,容易劝退。
3.5 集成验证
四步走完,怎么验证?把U-Boot、内核zImage、设备树dtb、根文件系统镜像烧到板子上,上电看串口log。
我一般用SD卡启动调试:
- SD卡分区:FAT32放U-Boot和内核,ext4放根文件系统
- U-Boot环境变量设置:
setenv bootcmd 'fatload mmc 0:1 0x12000000 zImage; fatload mmc 0:1 0x13000000 imx6ull.dtb; bootz 0x12000000 - 0x13000000' - 启动后执行
ls /、ifconfig、mount,确认系统正常
经验之谈:第一次启动如果卡在Kernel panic - not syncing: VFS: Unable to mount root fs,别慌。90%是根文件系统路径或格式不对。检查root=参数和内核是否支持对应文件系统。
嗯,这套流程我走了不下50遍。从最开始照着教程一步步敲,到后来闭着眼都能配。你只要亲手做一遍,后面就通了。