2. 嵌入式Linux基础
说实话,很多刚入行的朋友觉得嵌入式Linux开发最难的是写驱动、调协议。但我个人的经验是——环境搭不好,后面全是坑。我在项目里见过太多人,花了两周调一个bug,最后发现是交叉编译链版本不对。嗯,咱们先把地基打牢。
这一章,我会带你走一遍完整的开发环境搭建流程。包括交叉编译工具链、TFTP/NFS服务、U-Boot和内核编译,还有根文件系统制作。你跟着做一遍,后面写代码、调板子会顺手很多。
2.1 交叉编译工具链:为什么需要它?
你想想看,你的开发主机是x86架构,目标板是ARM架构。x86的机器编译出来的程序,ARM芯片根本跑不了。所以我们需要交叉编译工具链——在x86上编译出ARM能运行的二进制文件。
我个人习惯用Linaro提供的预编译工具链,稳定、省事。以i.MX6ULL为例,我们选gcc-arm-linux-gnueabihf。
安装步骤
- 下载工具链:从Linaro官网或ARM官方下载
gcc-arm-10.3-2021.07-x86_64-arm-linux-gnueabihf.tar.xz - 解压到指定目录:
sudo tar -xvf gcc-arm-*.tar.xz -C /opt/ - 添加环境变量:编辑
~/.bashrc,加入export PATH=$PATH:/opt/gcc-arm-10.3-2021.07-x86_64-arm-linux-gnueabihf/bin - 验证安装:
arm-linux-gnueabihf-gcc --version
/opt下建一个toolchains目录,把不同架构的工具链都放进去。以后换芯片平台,改个PATH就行,不用重新折腾。
2.2 TFTP与NFS服务:让板子“吃”到文件
板子刚上电,没有操作系统,怎么把内核和文件系统传进去?这时候就需要TFTP和NFS了。说白了,TFTP用来传内核镜像,NFS用来挂载根文件系统——这样你改代码后不用反复烧写SD卡,直接重启板子就能看到效果。
TFTP服务配置
# 安装TFTP服务
sudo apt-get install tftpd-hpa
# 创建tftp根目录
sudo mkdir -p /tftpboot
sudo chmod 777 /tftpboot
# 修改配置文件 /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure -c -s"
# 重启服务
sudo systemctl restart tftpd-hpa
NFS服务配置
# 安装NFS服务
sudo apt-get install nfs-kernel-server
# 创建NFS共享目录
sudo mkdir -p /nfsroot
sudo chmod 777 /nfsroot
# 编辑 /etc/exports,添加一行
/nfsroot *(rw,sync,no_subtree_check,no_root_squash)
# 重启服务
sudo systemctl restart nfs-kernel-server
sudo ufw disable试试。
2.3 U-Boot编译:板子的“第一段代码”
U-Boot是板子上电后第一个跑的程序。它负责初始化硬件、加载内核。我一般从芯片厂商的官方仓库拉代码,比如NXP的imx_v2020.04分支。
编译步骤
# 下载U-Boot源码
git clone https://source.codeaurora.org/external/imx/uboot-imx
cd uboot-imx
git checkout imx_v2020.04
# 配置(以mx6ull_14x14_evk为例)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_evk_defconfig
# 编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4
# 编译产物:u-boot.imx(带IVT头的镜像)
CROSS_COMPILE必须指定为你的交叉编译链前缀,不要漏掉后面的短横线。漏了的话,编译会调用本机的gcc,出来的东西板子跑不了。
2.4 Linux内核编译:定制你的系统核心
内核是操作系统的核心。对于工控网关,我们通常需要裁剪掉不需要的驱动,只保留网络、存储、串口等必要模块。这样内核小、启动快、也更安全。
编译步骤
# 下载内核源码
git clone https://source.codeaurora.org/external/imx/linux-imx
cd linux-imx
git checkout imx_5.4.70_2.3.0
# 配置内核
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
# 如果需要微调,运行菜单配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
# 编译内核和设备树
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 zImage
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 dtbs
# 编译产物:arch/arm/boot/zImage 和 arch/arm/boot/dts/*.dtb
menuconfig里上千个选项很容易让人懵。我的做法是:先用默认配置编译通过,确保环境没问题。然后再逐步裁剪。一步到位往往出问题。
2.5 根文件系统制作:Buildroot vs Yocto
根文件系统是Linux启动后挂载的“/”目录,里面放着所有用户态程序、库、配置文件。制作根文件系统,主流方案有两个:Buildroot和Yocto。
| 对比项 | Buildroot | Yocto |
|---|---|---|
| 学习曲线 | 低,配置简单 | 高,概念多(Recipe、Layer、BitBake) |
| 构建速度 | 快,单次编译 | 慢,但增量编译做得好 |
| 定制灵活性 | 中等,适合固定需求 | 极高,适合复杂产品 |
| 包管理 | 无,编译时全静态 | 支持RPM/DEB包生成 |
| 适用场景 | 原型验证、小批量产品 | 大规模量产、需要长期维护 |
Buildroot快速上手
# 下载Buildroot
wget https://buildroot.org/downloads/buildroot-2023.02.tar.gz
tar -xvf buildroot-2023.02.tar.gz
cd buildroot-2023.02
# 配置(选择目标芯片架构)
make menuconfig
# Target options -> Target Architecture = ARM (little endian)
# Target options -> Target Binary Format = ELF
# Target options -> Target Architecture Variant = cortex-A7
# Toolchain -> Toolchain type = External toolchain
# Toolchain -> Toolchain = Custom toolchain
# Toolchain -> Toolchain path = /opt/gcc-arm-10.3-2021.07-x86_64-arm-linux-gnueabihf
# System configuration -> Root filesystem overlay directory = /path/to/your/overlay
# 编译
make -j4
# 编译产物:output/images/rootfs.tar 或 rootfs.ext4
Yocto快速上手(简版)
# 下载Poky(Yocto参考发行版)
git clone git://git.yoctoproject.org/poky
cd poky
git checkout dunfell
# 初始化构建环境
source oe-init-build-env build
# 修改 conf/local.conf
MACHINE ??= "imx6ull-14x14-evk"
DL_DIR ?= "/path/to/downloads"
SSTATE_DIR ?= "/path/to/sstate-cache"
# 修改 conf/bblayers.conf,添加meta-freescale层
# 编译核心镜像
bitbake core-image-minimal
# 编译产物:tmp/deploy/images/imx6ull-14x14-evk/*
2.6 本章小结:你得到了什么?
走完这一章,你的开发主机应该具备了以下能力:
- 能用
arm-linux-gnueabihf-gcc编译ARM程序 - TFTP服务已启动,板子能从主机下载内核镜像
- NFS服务已启动,板子能挂载主机的文件系统
- 能编译出U-Boot镜像(
u-boot.imx) - 能编译出Linux内核(
zImage+.dtb) - 能用Buildroot或Yocto制作根文件系统
这些工具和服务,就是你后面所有开发工作的基础。别嫌麻烦,每一步都亲手敲一遍。我当年第一次搭环境时,光NFS就折腾了一下午——但搞通之后,后面调驱动、跑应用就顺畅多了。