第二章 开发环境搭建:交叉编译工具链配置、Linux内核裁剪与编译、根文件系统制作、TFTP/NFS调试环境搭建
好,咱们正式开始动手了。这一章要解决的是「工欲善其事,必先利其器」的问题。嵌入式开发不像你在PC上写个Hello World那么简单,你写的代码最终要跑到ARM、MIPS或者RISC-V的板子上。所以,你得先搭好一座桥——交叉编译环境。
我个人习惯把这一章分成四个部分来讲:工具链、内核、根文件系统、调试环境。咱们一个一个来。
2.1 交叉编译工具链配置
什么是交叉编译?说白了,就是在你的x86电脑上,编译出能在ARM芯片上跑的程序。你想想看,你的开发板可能只有256MB内存,连个完整的GCC都跑不起来,更别说编译Linux内核了。所以,我们得用「交叉编译工具链」。
工具链的选择,我建议你直接用Linaro提供的预编译版本。为什么?因为我自己踩过坑——曾经花了一周时间从源码编译GCC,结果各种依赖问题,最后发现Linaro的版本稳定又好用。
常用工具链下载地址(以ARM Cortex-A系列为例):
- 32位ARM:gcc-arm-linux-gnueabihf
- 64位ARM:gcc-aarch64-linux-gnu
安装其实很简单,解压后配置环境变量就行:
# 下载并解压
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-*.tar.xz -C /opt/
# 配置环境变量(建议写到 ~/.bashrc 里)
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm
小技巧: 我习惯把工具链放在 /opt 目录下,然后在 ~/.bashrc 里加一行 source 脚本。这样每次打开终端,环境变量自动生效,不用重复配置。
验证是否安装成功:
arm-linux-gnueabihf-gcc --version
# 如果能显示版本号,说明配置成功
嗯,这里要注意:不同版本的GCC对内核编译的支持不一样。我曾经用GCC 9.x编译Linux 4.14内核,结果报了一堆语法错误。后来换成GCC 7.5就没事了。所以,建议内核版本和工具链版本匹配。
2.2 Linux内核裁剪与编译
内核裁剪,说白了就是「减肥」。你的开发板Flash可能只有16MB,而默认的内核编译出来有几十MB,根本放不下。所以,我们要把不需要的功能去掉。
我个人习惯先拿一个默认配置,然后一步步裁剪。以NXP i.MX6ULL为例:
# 下载内核源码
wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.14.98.tar.xz
tar -xvf linux-4.14.98.tar.xz
cd linux-4.14.98
# 使用默认配置
make imx_v7_defconfig
# 进入菜单配置界面
make menuconfig
在menuconfig界面里,我一般会做以下几件事:
- 关闭不需要的驱动:比如你的板子没有WiFi模块,就把Wireless相关的全关掉
- 关闭调试选项:Kernel hacking里的很多调试选项在生产环境可以关掉
- 精简文件系统支持:只保留你需要的文件系统类型,比如ext4、yaffs2
警告: 裁剪内核时,千万别把启动必须的驱动给关了。比如串口驱动(UART)、中断控制器(GIC)、定时器(Timer)。我曾经有一次把串口驱动关了,结果内核启动后没有任何输出,折腾了半天才发现是这个问题。
配置完成后,开始编译:
make -j4 zImage
make -j4 dtbs
make modules
编译完成后,你会得到:
- arch/arm/boot/zImage —— 内核镜像
- arch/arm/boot/dts/imx6ull-14x14-evk.dtb —— 设备树文件
- 各个内核模块(.ko文件)
我一般会把zImage和dtb文件单独拿出来,放到TFTP目录下,方便调试。
2.3 根文件系统制作
内核启动后,需要挂载根文件系统。根文件系统里有什么?说白了,就是/bin、/sbin、/etc、/lib这些目录,还有你写的应用程序。
制作根文件系统,我推荐用Buildroot。它比Yocto轻量,比BusyBox功能全。我个人在项目里用了好几年Buildroot,稳定性不错。
# 下载Buildroot
wget https://buildroot.org/downloads/buildroot-2020.02.tar.gz
tar -xvf buildroot-2020.02.tar.gz
cd buildroot-2020.02
# 配置
make menuconfig
在配置界面里,你需要设置:
- Target options —— 选择你的CPU架构(ARM)
- Toolchain —— 选择外部工具链(就是我们刚才配置的那个)
- System configuration —— 设置主机名、root密码等
- Target packages —— 选择你需要的软件包(比如dropbear用于SSH)
我的经验: 第一次用Buildroot时,我建议先选一个最小的配置,只包含BusyBox和基本的库文件。等系统跑起来了,再慢慢加功能。这样出了问题容易定位。
配置完成后,直接编译:
make -j4
编译完成后,在output/images目录下会生成rootfs.tar、rootfs.cpio等文件。我一般用rootfs.tar,解压到NFS目录或者烧录到Flash里。
2.4 TFTP/NFS调试环境搭建
调试环境搭建,是嵌入式开发中最能提升效率的一环。你想想看,每次修改代码都要重新烧录Flash,那得多浪费时间?所以,我们要用TFTP下载内核,用NFS挂载根文件系统。
2.4.1 TFTP服务器配置
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"
# 重启服务
sudo systemctl restart tftpd-hpa
把编译好的zImage和dtb文件复制到/tftpboot目录下:
cp arch/arm/boot/zImage /tftpboot/
cp arch/arm/boot/dts/imx6ull-14x14-evk.dtb /tftpboot/
2.4.2 NFS服务器配置
NFS用于让开发板通过网络挂载根文件系统。这样你修改了应用程序,直接重新编译,开发板重启后就能看到新程序,不用烧录。
# 安装NFS服务器
sudo apt-get install nfs-kernel-server
# 创建NFS共享目录
sudo mkdir -p /nfs/rootfs
sudo chmod 777 /nfs/rootfs
# 解压根文件系统到NFS目录
sudo tar -xvf output/images/rootfs.tar -C /nfs/rootfs
# 修改配置文件 /etc/exports
# 添加一行:
/nfs/rootfs *(rw,sync,no_root_squash,no_subtree_check)
# 重启服务
sudo systemctl restart nfs-kernel-server
避坑指南: 我曾经遇到过NFS挂载后,开发板上的应用程序无法写文件的问题。后来发现是no_root_squash没加。这个选项允许root用户以root权限访问NFS目录,不加的话,root会被映射成nobody,权限不够。
2.4.3 U-Boot启动参数设置
最后,在U-Boot里设置启动参数,让开发板从TFTP下载内核,从NFS挂载根文件系统:
setenv serverip 192.168.1.100 # 主机IP
setenv ipaddr 192.168.1.10 # 开发板IP
setenv netmask 255.255.255.0
setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-14x14-evk.dtb; bootz 80800000 - 83000000'
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.100:/nfs/rootfs rw ip=192.168.1.10'
saveenv
boot
嗯,这里要注意IP地址的设置。我建议把主机的IP设为静态IP,不然每次路由器重启,IP变了,开发板就找不到服务器了。
2.5 验证与测试
环境搭建完成后,我们来验证一下。开发板上电,串口输出应该能看到:
U-Boot 2020.04
...
Net: FEC
Using FEC device
TFTP from server 192.168.1.100; our IP address is 192.168.1.10
Filename 'zImage'.
Load address: 0x80800000
Loading: #################################################################
done
Bytes transferred = 4567890 (4.5 MiB)
...
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
...
VFS: Mounted root (nfs filesystem) on device 0:12
...
Starting network: OK
Starting dropbear: OK
Welcome to Buildroot
buildroot login: root
看到这个登录提示,说明你的开发环境搭建成功了!
总结一下: 这一章我们做了四件事——配置交叉编译工具链、裁剪并编译Linux内核、用Buildroot制作根文件系统、搭建TFTP/NFS调试环境。这套环境搭好了,后面的开发工作就会顺畅很多。我个人建议你把每一步的配置都记录下来,写成脚本,下次换项目时直接复用。
下一章,我们会开始移植安防协议栈的核心模块。到时候,这套调试环境就会派上大用场了。