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 本章知识体系

下面这张图,把本章的核心内容串起来了。你可以把它当作一个检查清单,看看自己漏了哪一步。

开发环境准备知识体系 开发环境准备知识体系 Linux主机环境 交叉编译工具链 QEMU模拟器 Git版本控制 开发环境核心流程 1. 安装Linux主机 + 基础工具 2. 安装交叉编译工具链 3. 配置QEMU模拟器验证 4. 用Git管理所有代码和配置 四个模块缺一不可,建议按顺序搭建

2.6 环境验证清单

环境搭好了,怎么知道对不对?我列个检查清单,你照着跑一遍:

  1. 检查gcc:gcc --version 能看到版本号
  2. 检查交叉编译器:aarch64-none-linux-gnu-gcc --version 能正常输出
  3. 检查QEMU:qemu-system-aarch64 --version 能看到版本
  4. 检查Git:git --version 能看到版本,git config --list 能看到你的用户名和邮箱
  5. 编译测试:写一个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"

到这里,你的开发环境就准备好了。后面所有章节的实验,都基于这个环境。如果哪一步卡住了,别硬撑,回头检查一下。我曾经因为一个环境变量没配好,浪费了一整天。嗯,这种坑踩过一次就够了。