2、嵌入式开发环境搭建:交叉编译工具链安装、Linux系统配置、SSH与NFS网络调试环境
好,咱们正式开始动手了。
这一章,说白了就是给你的开发机“装上武器”。没有交叉编译工具链,你写的代码在PC上跑得再欢,ARM板子也看不懂。没有SSH和NFS,你每次改个文件都要插拔SD卡,那效率低得让人抓狂。我当年刚入行时,就吃过这个亏——代码改了一整天,烧录进去发现有个小bug,又得重新编译、烧录、重启……来回折腾了十几遍。后来搭好了NFS,才真正体会到什么叫“丝滑开发”。
2.1 交叉编译工具链:为什么需要它?
你想想看,你的PC是x86架构,而嵌入式板子通常是ARM架构。x86的编译器编译出来的程序,ARM根本看不懂。所以我们需要一个“跨平台”的编译器——在x86上运行,但生成ARM能执行的机器码。这就是交叉编译工具链。
我个人习惯用Linaro提供的工具链,稳定且社区支持好。当然,你也可以用芯片厂商提供的SDK里的工具链,比如NXP的、TI的,本质都一样。
2.1.1 安装步骤(以ARM Cortex-A7为例)
- 下载工具链
去Linaro官网下载gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz。别下错了版本,注意是arm-linux-gnueabihf,带硬浮点优化的。 - 解压到指定目录
sudo mkdir -p /opt/toolchains
sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/toolchains/
- 配置环境变量
编辑~/.bashrc,在末尾添加:
export PATH=$PATH:/opt/toolchains/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm
然后 source ~/.bashrc 使其生效。
- 验证安装
arm-linux-gnueabihf-gcc --version
如果看到版本信息,恭喜你,第一步走通了。
/etc/profile 里,这样所有用户都能用。但如果你只是个人开发,改 ~/.bashrc 就够了,避免污染系统环境。
2.2 Linux系统配置:让开发机更顺手
嗯,这里要注意。很多新手拿到Ubuntu第一件事就是装IDE,其实先把基础环境配好,后面能省一半时间。
2.2.1 安装必要软件包
sudo apt update
sudo apt install -y build-essential git vim ssh nfs-kernel-server minicom
这几个包的作用:
build-essential:编译必备,gcc、make等git:版本管理,你总不想代码丢了重写吧vim:编辑器,我习惯用vim,但用nano也行ssh:远程登录,后面调试全靠它nfs-kernel-server:网络文件系统,共享目录用minicom:串口工具,调试板子必备
2.2.2 配置静态IP(开发机)
为什么用静态IP?因为你的板子每次启动都要通过NFS挂载你的目录,如果IP变了,板子就找不到你了。我曾经在实验室里因为路由器重启导致IP变了,板子挂载失败,排查了半天……后来老老实实配了静态IP。
编辑 /etc/netplan/01-netcfg.yaml(Ubuntu 18.04+):
network:
version: 2
ethernets:
eth0:
dhcp4: no
addresses:
- 192.168.1.100/24
gateway4: 192.168.1.1
nameservers:
addresses: [8.8.8.8, 114.114.114.114]
然后 sudo netplan apply 生效。
2.3 SSH网络调试环境
SSH,说白了就是让你能远程登录板子,像操作本地终端一样。我调试时,通常开三个终端:一个SSH到板子看日志,一个本地编译代码,一个用SCP传文件。效率很高。
2.3.1 板子端开启SSH服务
大多数嵌入式Linux系统默认不带SSH服务,需要自己移植。但如果你用的是Buildroot或Yocto构建的系统,可以在配置时勾选openssh包。
手动安装方法(以ARM板为例):
- 下载openssh源码,交叉编译
- 将编译好的
sshd、ssh、ssh-keygen等二进制文件拷贝到板子的/usr/sbin/和/usr/bin/ - 生成密钥对:
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key - 启动服务:
/usr/sbin/sshd
嗯,这里要注意。第一次启动时,板子可能没有 /var/empty 目录,需要手动创建:
mkdir -p /var/empty
chmod 755 /var/empty
2.3.2 从开发机SSH登录板子
ssh root@192.168.1.101
第一次登录会提示确认指纹,输入yes即可。如果提示“Permission denied”,检查板子上 /etc/ssh/sshd_config 是否允许root登录:
PermitRootLogin yes
date -s "2025-01-15 10:30:00" 设置正确时间,或者配置NTP同步。
2.4 NFS网络调试环境
NFS,网络文件系统。它的作用是把开发机上的一个目录共享给板子,板子启动时直接挂载这个目录作为根文件系统。这样你改代码、编译、运行,全在开发机上操作,板子实时看到更新。不用烧录、不用重启,爽不爽?
2.4.1 开发机端配置NFS服务器
- 创建共享目录
sudo mkdir -p /srv/nfs/rootfs
sudo chmod 777 /srv/nfs/rootfs
- 编辑导出文件
编辑/etc/exports,添加一行:
/srv/nfs/rootfs 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)
参数说明:
rw:读写权限sync:同步写入,保证数据一致性no_subtree_check:提高性能no_root_squash:允许板子上的root用户拥有完整权限。这个很重要,否则板子上创建的文件属主会变成nobody
- 重启NFS服务
sudo exportfs -a
sudo systemctl restart nfs-kernel-server
- 验证共享是否生效
showmount -e localhost
应该能看到 /srv/nfs/rootfs 被列出。
2.4.2 板子端挂载NFS
在板子的U-Boot启动参数中,设置根文件系统为NFS。以常见的 bootargs 为例:
setenv bootargs 'console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.100:/srv/nfs/rootfs rw ip=192.168.1.101:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off'
参数解释:
root=/dev/nfs:告诉内核根文件系统在NFS上nfsroot=服务器IP:共享目录ip=板子IP:服务器IP:网关:子网掩码::网卡名:off
保存并启动板子。如果一切正常,板子会从NFS启动,你可以在开发机上修改 /srv/nfs/rootfs 下的文件,板子立即生效。
ping 192.168.1.100 测试。如果不通,检查网线、IP配置、防火墙。我遇到过最坑的一次是Windows防火墙把NFS端口给拦了,关掉就好了。
2.5 实战:验证整个环境
好,环境搭好了,我们来写个简单的“Hello World”验证一下。
- 在开发机上编写代码
cd /srv/nfs/rootfs
vim hello.c
#include <stdio.h>
int main() {
printf("Hello from ARM board!\n");
return 0;
}
- 交叉编译
arm-linux-gnueabihf-gcc -o hello hello.c
- SSH登录板子,运行程序
ssh root@192.168.1.101
cd /
./hello
如果看到 Hello from ARM board!,恭喜你,整个开发环境搭建成功!
下一章,我们会开始写第一个真正的嵌入式程序——点亮LED。别小看这个,它背后涉及GPIO控制、寄存器操作、设备树配置,是嵌入式开发的“Hello World”。准备好了吗?