3. 嵌入式Linux系统构建:交叉编译环境搭建、U-Boot移植与配置、Linux内核裁剪与编译、根文件系统制作

嵌入式Linux系统构建,说白了就是给硬件“装脑子”。我见过不少工程师,拿到一块新板子就急着写应用,结果底层一跑就崩。嗯,这章咱们就把这套流程捋清楚。

核心流程:交叉编译工具链 → Bootloader(U-Boot)→ Linux内核 → 根文件系统(Rootfs)。这四步走完,你的板子才算真正“活”了。

嵌入式Linux系统构建流程 交叉编译工具链 U-Boot移植 内核裁剪编译 根文件系统 关键说明: • 工具链是基础,架构选错后面全白搭(ARM vs MIPS vs RISC-V) • U-Boot负责硬件初始化,引导内核启动 • 内核裁剪决定功能集与驱动支持,根文件系统决定用户空间

3.1 交叉编译环境搭建

交叉编译,就是在一台高性能PC(x86)上,编译出能在ARM板子上跑的程序。你想想看,板子那点算力,编译个内核得等到猴年马月?

我个人习惯用Linaro GCC,稳定且社区活跃。当然,你也可以用Buildroot或Yocto自带的工具链,但新手我建议先手动搭一遍,理解原理。

我的经验:工具链版本一定要和内核匹配。我曾经用gcc 9.x编译Linux 4.19的内核,结果莫名奇妙报__builtin_bswap16错误,折腾了两天。后来换成gcc 8.3,一次过。

搭建步骤

  1. 下载工具链:从Linaro官网或ARM官网下载预编译包。例如:gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
  2. 解压到指定目录:tar -xvf gcc-linaro-*.tar.xz -C /opt/toolchains/
  3. 设置环境变量:编辑~/.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-
  1. 验证:运行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秒。

裁剪流程

  1. 获取内核源码:从kernel.org或芯片厂商BSP包获取。
  2. 配置内核:运行make menuconfig,进入图形界面。
  3. 关键裁剪项:
    • 关闭无用架构支持(只保留ARM)
    • 关闭无用驱动(蓝牙、Wi-Fi、USB Gadget等)
    • 保留必要驱动(串口、网卡、GPIO、I2C、SPI、看门狗)
    • 文件系统支持:ext4、squashfs(只读根文件系统用)
  4. 编译:make zImage -j4(ARM架构生成zImage)
  5. 编译设备树: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快速上手

  1. 下载:git clone git://git.buildroot.net/buildroot
  2. 配置:make menuconfig,选择目标架构(ARM)、工具链(外部工具链)、包(busybox、dropbear SSH、ntp等)
  3. 编译:make -j4,输出在output/images/目录
  4. 生成镜像: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卡启动调试:

  1. SD卡分区:FAT32放U-Boot和内核,ext4放根文件系统
  2. U-Boot环境变量设置:setenv bootcmd 'fatload mmc 0:1 0x12000000 zImage; fatload mmc 0:1 0x13000000 imx6ull.dtb; bootz 0x12000000 - 0x13000000'
  3. 启动后执行ls /、ifconfig、mount,确认系统正常

经验之谈:第一次启动如果卡在Kernel panic - not syncing: VFS: Unable to mount root fs,别慌。90%是根文件系统路径或格式不对。检查root=参数和内核是否支持对应文件系统。

嗯,这套流程我走了不下50遍。从最开始照着教程一步步敲,到后来闭着眼都能配。你只要亲手做一遍,后面就通了。