3. QEMU源码编译:从源码编译QEMU、配置目标架构与常见错误处理

说实话,很多做嵌入式Linux的朋友一开始都习惯直接 apt install qemu-system-arm。但当你需要定制QEMU特性、打补丁、或者调试QEMU自身行为时,从源码编译就成了绕不开的一步。我个人习惯在项目初期就把QEMU源码环境搭好,后面做板级仿真、外设模拟会顺手很多。

3.1 为什么非要自己编译QEMU?

你可能会问:包管理器装的不香吗?嗯,这里有几个场景,包管理器搞不定:

  • 定制目标架构:默认包只编译了常见架构,你想模拟某个冷门开发板?得自己来。
  • 打补丁调试:我在项目中遇到过QEMU模拟某款网卡时丢包,需要加调试打印,必须从源码编译。
  • 版本锁定:团队统一用QEMU 8.2.0,但Ubuntu源里只有7.2,源码编译最稳。
  • 性能优化:开启TCG加速、调整内存模型,这些编译选项包管理器给不了你。
一句话总结:包管理器装的是“够用”,源码编译是“可控”。做嵌入式系统,可控比什么都重要。

3.2 编译前的准备:依赖与源码获取

先别急着 git clone,依赖没装全的话,编译到一半报错会让你抓狂。我踩过这个坑,所以列个清单给你:

依赖类别 关键包名(Ubuntu/Debian) 说明
基础编译工具 build-essential, pkg-config, meson, ninja-build Meson是QEMU 6.0+的构建系统,必须装
图形/显示 libsdl2-dev, libgtk-3-dev, libvte-dev 没有这些,你只能跑无头模式(-nographic)
网络支持 libslirp-dev, libpcap-dev 用户态网络和桥接网络需要
虚拟化加速 libvirglrenderer-dev, libdrm-dev 开启KVM加速时用
文档/测试 python3-sphinx, texinfo 编译文档时需要,可跳过

装依赖的命令很简单:

sudo apt update
sudo apt install build-essential pkg-config meson ninja-build \
                 libsdl2-dev libgtk-3-dev libvte-dev \
                 libslirp-dev libpcap-dev \
                 python3-sphinx texinfo
我的习惯:先装全了再编译,省得反复 apt install 打断思路。如果你磁盘空间紧张,可以只装基础+目标架构需要的依赖。

源码获取,我推荐用官方git仓库,方便切换版本:

git clone https://gitlab.com/qemu-project/qemu.git
cd qemu
git checkout v8.2.0  # 锁定稳定版本

3.3 配置目标架构:configure与Meson选项

QEMU的配置系统从6.0开始全面转向Meson。但入口还是 configure 脚本,它会调用Meson做实际工作。说白了,你只需要跟 configure 打交道。

配置的核心是 --target-list 参数。默认编译所有架构,耗时很长。我建议只选你需要的:

./configure --target-list=arm-softmmu,aarch64-softmmu,riscv64-softmmu \
            --enable-slirp \
            --enable-kvm \
            --enable-debug \
            --prefix=/opt/qemu-8.2

解释一下关键选项:

  • --target-list:指定目标架构。格式是 架构-软MMU(系统模式)或 架构-linux-user(用户模式)。
  • --enable-slirp:开启用户态网络,仿真时虚拟机可以直接上网。
  • --enable-kvm:宿主机支持KVM时,开启硬件加速。
  • --enable-debug:保留调试符号,方便后续用GDB调试QEMU本身。
  • --prefix:安装路径,避免污染系统目录。

常见的架构后缀对照表:

目标架构 系统模式(softmmu) 用户模式(linux-user) 典型用途
ARM 32位 arm-softmmu arm-linux-user STM32MP1、Cortex-A系列
AArch64 aarch64-softmmu aarch64-linux-user 树莓派4、Raspberry Pi OS
RISC-V 64位 riscv64-softmmu riscv64-linux-user SiFive Unleashed、OpenSBI
x86_64 x86_64-softmmu x86_64-linux-user PC仿真、KVM测试
注意:如果你只编译用户模式(linux-user),仿真时只能运行单个二进制文件,不能启动完整操作系统。做嵌入式Linux系统仿真,一定要选 softmmu。

3.4 编译与安装

配置成功后,Meson会生成构建目录(默认在 build/)。编译命令很简单:

make -j$(nproc)  # 并行编译,充分利用CPU核心

我第一次编译QEMU 8.2时,只选了三个架构,大概花了15分钟。如果全架构编译,半小时起步。你可以去喝杯咖啡。

编译完成后,安装到指定目录:

sudo make install

验证安装:

/opt/qemu-8.2/bin/qemu-system-aarch64 --version

如果看到版本号输出,恭喜你,编译成功。

3.5 常见编译错误与避坑指南

编译QEMU很少一帆风顺。我把自己遇到过的典型错误整理出来,你遇到了直接对照解决。

错误1:Meson版本过低

现象:configure 报错 Meson version 0.61.0 or higher required。

原因:系统自带的Meson太老。Ubuntu 20.04默认是0.53,不够用。

解决:

pip3 install --upgrade meson
# 或者用pip3安装最新版
pip3 install meson==1.2.0
我曾经:在Ubuntu 18.04上折腾了一下午,最后发现是Meson版本问题。后来我养成了习惯,编译前先 meson --version 看一眼。

错误2:缺少glib-2.56

现象:configure 报错 glib-2.56 >= 2.56 is required。

原因:系统glib库版本太低。老发行版常见。

解决:

sudo apt install libglib2.0-dev
# 如果还不行,手动编译glib或升级系统

错误3:Python3路径不对

现象:configure 报错 Python not found 或 Python version too old。

原因:系统默认python指向python2,或者python3没装。

解决:

sudo apt install python3 python3-pip
# 指定python3路径
./configure --python=/usr/bin/python3

错误4:编译时链接失败(undefined reference)

现象:make 过程中出现大量 undefined reference to 'xxx'。

原因:通常是某个依赖库没装,或者版本不匹配。

解决:

  • 检查 configure 输出,看哪些feature被标记为 NO。
  • 安装对应的 -dev 包。
  • 清理构建目录重新配置:rm -rf build/ 然后重新 ./configure。

错误5:KVM权限问题

现象:编译成功,但运行时报错 Could not access KVM kernel module: Permission denied。

原因:当前用户不在 kvm 用户组。

解决:

sudo usermod -aG kvm $USER
# 重新登录或执行 newgrp kvm

3.6 知识体系:QEMU编译流程全景

下面这张图帮你理清整个编译流程的脉络:

QEMU源码编译流程全景图 QEMU源码编译流程全景 1. 环境准备 2. 获取源码 3. 配置目标 4. 编译(make) 5. 安装(make install) 6. 验证运行 关键配置参数: --target-list=arm-softmmu,aarch64-softmmu,riscv64-softmmu --enable-slirp --enable-kvm --enable-debug --prefix=/opt/qemu-8.2 常见错误与解决: • Meson版本过低 → pip3 install --upgrade meson • glib版本不足 → sudo apt install libglib2.0-dev • Python路径错误 → ./configure --python=/usr/bin/python3 • KVM权限问题 → sudo usermod -aG kvm $USER 整个流程从环境准备到验证运行,配置阶段是最容易出错的环节 建议每次修改配置后先清理构建目录(rm -rf build/)再重新配置

3.7 进阶技巧:定制化编译

如果你需要更精细的控制,这里有几个实用技巧:

  • 只编译特定设备:通过 --with-devices 选项指定,比如只编译virt开发板:--with-devices=arm-virt。
  • 开启TCG调试:--enable-tcg-interpreter 可以单步跟踪每条指令的翻译过程,调试内核时很有用。
  • 静态编译:--static 选项生成静态链接的QEMU,方便移植到其他环境。
  • 交叉编译:如果你想在x86上编译ARM架构的QEMU,需要设置交叉工具链:--cross-prefix=arm-linux-gnueabihf-。
我的经验:做嵌入式Linux仿真,我一般只编译 arm-softmmu 和 aarch64-softmmu,再加一个 riscv64-softmmu 做对比测试。够用就好,别贪多。

3.8 本章小结