2. 嵌入式Linux基础
做嵌入式Linux开发,环境搭建是第一步。这一步要是没弄好,后面全是坑。我见过太多新手卡在环境上,折腾一整天连个Hello World都跑不起来。说白了,开发环境就是你的武器库,武器不趁手,仗就没法打。
这一章,我们就把武器库备齐。包括Linux主机环境、交叉编译工具链、QEMU模拟器,还有Git版本控制。嗯,一个一个来。
本章核心目标:搭建一个可复用的嵌入式Linux开发环境,确保后续所有实验都能在这个环境上顺利运行。
2.1 Linux主机环境搭建
嵌入式Linux开发,首选Ubuntu。我个人习惯用Ubuntu 20.04 LTS或22.04 LTS,这两个版本稳定,社区支持好,遇到问题容易搜到答案。
如果你用的是Windows,别慌。装个虚拟机就行。我推荐VirtualBox + Ubuntu Server,轻量、免费、够用。
2.1.1 安装必要软件包
系统装好后,第一件事就是装开发工具。打开终端,执行:
sudo apt update
sudo apt upgrade -y
sudo apt install -y build-essential git vim curl wget \
libncurses-dev flex bison openssl libssl-dev \
dkms libelf-dev libudev-dev libpci-dev \
libiberty-dev autoconf automake texinfo \
python3 python3-pip python3-venv \
qemu-system-arm qemu-system-aarch64 \
u-boot-tools device-tree-compiler
这里面的包,每一个都有用。build-essential是编译基础,git是版本控制,qemu-system-*是模拟器。我在项目中遇到过有人漏装了libncurses-dev,结果编译内核时菜单配置界面死活出不来,折腾了半天才发现是少了个库。
小技巧:装完后可以用 dpkg -l | grep <包名> 检查是否安装成功。比如 dpkg -l | grep qemu 看看QEMU装上了没。
2.1.2 配置SSH和网络
嵌入式开发经常需要远程操作。建议把SSH服务打开:
sudo apt install -y openssh-server
sudo systemctl enable ssh
sudo systemctl start ssh
网络方面,如果你的开发板需要NFS或TFTP,建议把防火墙配置好。我一般直接关掉ufw,省事:
sudo ufw disable
注意:生产环境别这么干。开发环境图方便可以,但记得只在局域网内使用。
2.2 交叉编译工具链安装
交叉编译,说白了就是在你的PC上编译出能在ARM、RISC-V等其他架构上运行的代码。为什么需要这个?因为嵌入式设备性能弱,跑不了编译器。你想想看,一个只有64MB内存的板子,让它跑gcc,那不是开玩笑吗?
2.2.1 工具链的选择
市面上工具链很多,我推荐用Linaro提供的预编译版本,稳定、更新及时。以ARM 64位为例:
| 架构 | 工具链名称 | 下载前缀 |
|---|---|---|
| ARM 32位 | arm-linux-gnueabihf | gcc-arm-<版本>-x86_64-arm-linux-gnueabihf |
| ARM 64位 | aarch64-linux-gnu | gcc-arm-<版本>-x86_64-aarch64-linux-gnu |
| RISC-V 64位 | riscv64-linux-gnu | riscv64-unknown-linux-gnu |
2.2.2 安装步骤
以aarch64为例,我习惯把工具链放在 /opt/toolchains 下:
sudo mkdir -p /opt/toolchains
cd /opt/toolchains
sudo wget https://developer.arm.com/-/media/Files/downloads/gnu/11.2-2022.02/binrel/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz
sudo tar -xf gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz
sudo rm gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz
然后配置环境变量。我个人习惯写到 ~/.bashrc 里:
echo 'export PATH=$PATH:/opt/toolchains/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin' >> ~/.bashrc
source ~/.bashrc
验证一下:
aarch64-none-linux-gnu-gcc --version
看到版本信息,就说明装好了。
避坑指南:我曾经遇到过工具链版本和内核版本不匹配,导致编译出来的内核启动就崩溃。建议工具链版本和内核版本保持对应,比如Linux 5.10内核用gcc 10.x或11.x比较稳妥。
2.3 QEMU模拟器配置
QEMU是个好东西。没有开发板?没关系,QEMU能模拟。我在项目中经常先用QEMU验证代码逻辑,没问题了再烧到真板上。这样调试效率高很多。
2.3.1 安装QEMU
前面已经装过了,这里再确认一下:
qemu-system-aarch64 --version
如果没装,用apt补上:
sudo apt install -y qemu-system-arm qemu-system-aarch64 qemu-utils
2.3.2 快速验证:用QEMU启动一个ARM虚拟机
我们先用一个最简单的例子,验证QEMU能不能用。下载一个现成的ARM内核和根文件系统:
mkdir -p ~/qemu_test
cd ~/qemu_test
wget https://releases.linaro.org/components/kernel/uefi-linaro/latest/release/qemu-aarch64/QEMU_EFI.fd
wget http://releases.linaro.org/components/kernel/uefi-linaro/latest/release/qemu-aarch64/Image
wget http://releases.linaro.org/components/kernel/uefi-linaro/latest/release/qemu-aarch64/vexpress64-openembedded_lamp-armv8-gcc-4.9_20161014-729.img.gz
gunzip vexpress64-openembedded_lamp-armv8-gcc-4.9_20161014-729.img.gz
然后启动:
qemu-system-aarch64 \
-machine virt \
-cpu cortex-a57 \
-smp 2 \
-m 1024 \
-bios QEMU_EFI.fd \
-kernel Image \
-drive if=none,file=vexpress64-openembedded_lamp-armv8-gcc-4.9_20161014-729.img,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-netdev user,id=net0 \
-device virtio-net-device,netdev=net0 \
-nographic
看到登录提示,就说明QEMU环境搭好了。用户名root,密码root(或者空密码,看镜像版本)。
注意:QEMU的启动参数很多,别被吓到。后面我们会专门讲如何定制QEMU启动脚本。你现在只需要知道它能跑就行。
2.4 版本控制工具Git的使用
Git是嵌入式开发的必备技能。没有Git,代码管理就是一团乱麻。我见过有人用U盘拷代码,版本号靠文件夹名字,什么"final_v2_真的不改了",结果改来改去自己都分不清。
2.4.1 Git基础配置
装好Git后,先配一下个人信息:
git config --global user.name "你的名字"
git config --global user.email "你的邮箱"
git config --global core.editor vim
git config --global color.ui auto
这些配置会写在 ~/.gitconfig 里。每次提交代码时,Git会用这些信息记录是谁改的。
2.4.2 嵌入式开发中的Git工作流
嵌入式项目通常包含多个仓库:内核、uboot、rootfs、应用代码。我推荐用 repo 工具来管理多仓库。不过那是后话,我们先掌握单仓库的基本操作。
常用的Git命令,我列个表:
| 操作 | 命令 | 说明 |
|---|---|---|
| 克隆仓库 | git clone <url> |
从远程拉取代码 |
| 查看状态 | git status |
看哪些文件改了 |
| 添加文件 | git add <file> |
把改动加入暂存区 |
| 提交 | git commit -m "消息" |
提交到本地仓库 |
| 推送 | git push |
推送到远程仓库 |
| 拉取 | git pull |
拉取远程最新代码 |
| 查看日志 | git log --oneline |
看提交历史 |
2.4.3 实战:用Git管理一个嵌入式项目
假设我们要管理一个uboot项目:
mkdir my_uboot
cd my_uboot
git init
echo "# My U-Boot Project" > README.md
git add README.md
git commit -m "Initial commit: add README"
# 添加uboot源码(假设已经下载好)
cp -r /path/to/u-boot-2023.04/* .
git add .
git commit -m "Import U-Boot 2023.04 source"
这样,你的uboot项目就有了完整的Git历史。以后改了什么,一目了然。
个人经验:提交信息要写清楚。别写"fix bug"这种废话,要写"fix: correct mmc driver timeout calculation for SDHC cards"。这样半年后回头看,你还能知道当时改了啥。
2.5 本章知识体系
下面这张图,把本章的核心内容串起来了。你可以把它当作一个检查清单,看看自己漏了哪一步。
2.6 环境验证清单
环境搭好了,怎么知道对不对?我列个检查清单,你照着跑一遍:
- 检查gcc:
gcc --version能看到版本号 - 检查交叉编译器:
aarch64-none-linux-gnu-gcc --version能正常输出 - 检查QEMU:
qemu-system-aarch64 --version能看到版本 - 检查Git:
git --version能看到版本,git config --list能看到你的用户名和邮箱 - 编译测试:写一个hello.c,用交叉编译器编译,看看能不能生成aarch64的可执行文件
# 测试交叉编译
cat > hello.c << EOF
#include <stdio.h>
int main() {
printf("Hello, Embedded Linux!\n");
return 0;
}
EOF
aarch64-none-linux-gnu-gcc -o hello hello.c
file hello
# 输出应该包含 "ELF 64-bit LSB executable, ARM aarch64"
到这里,你的开发环境就准备好了。后面所有章节的实验,都基于这个环境。如果哪一步卡住了,别硬撑,回头检查一下。我曾经因为一个环境变量没配好,浪费了一整天。嗯,这种坑踩过一次就够了。