2. 开发环境搭建

EDK II 的开发环境搭建是后续所有模块开发、集成与调试工作的基础。一个稳定、可复现的构建环境,能够显著降低“代码没问题但编译不过”“模拟器能跑真机跑不了”等问题的发生概率。本章围绕源码获取、目录结构认知、编译工具链配置,以及模拟器与真实平台两类运行环境的搭建展开,帮助读者建立一套可落地的环境准备流程。

一、核心原理:EDK II 构建体系的三层依赖

EDK II 的构建过程并非简单的“编译源码”,而是由三层依赖共同驱动:源码层(Packages、Modules、Libraries)、配置层(Conf 目录下的 DSC、FDF、DEC、INF 等描述文件)和工具层(BaseTools 与外部编译器)。理解这三层关系,是环境搭建不迷路的关键。

源码层提供模块与库的实现;配置层通过 DSC 决定“编译哪些模块、用哪些库实例”,通过 FDF 决定“固件镜像如何布局”,通过 DEC 声明包对外暴露的接口;工具层则由 EDK II 自带的 BaseTools 与宿主机的 GCC、Clang 或 MSVC 组成。三者缺一不可,且版本需要相互匹配。

EDK II 构建体系三层依赖关系 源码层 Packages(.dec) Modules(.inf) Libraries(.inf) PCD / GUID / Protocol 配置层 DSC(平台描述) FDF(镜像布局) DEC(包声明) Target.txt 工具层 BaseTools GCC / Clang NASM / IASL Python 3 描述与选择 调用与执行 三层版本需匹配:源码分支 ↔ BaseTools ↔ 外部编译器

二、源码获取与目录结构

EDK II 官方源码托管在 GitHub 的 tianocore/edk2 仓库。推荐使用 git clone 获取,并切换到稳定标签(如 edk2-stable202311)而非直接使用 master,以避免上游频繁变更导致构建失败。

git clone https://github.com/tianocore/edk2.git
cd edk2
git checkout edk2-stable202311
git submodule update --init --recursive

克隆完成后,顶层目录结构如下表所示。理解每个目录的职责,能帮助开发者快速定位模块、库与平台描述文件。

目录作用
MdePkg最基础的包,定义 UEFI/PI 规范中的协议、GUID、PPI 与基础库
MdeModulePkg通用模块与驱动实现,如 BDS、变量服务、文件系统驱动
OvmfPkgQEMU/OVMF 虚拟平台相关模块,模拟器环境常用
BaseToolsEDK II 构建工具集,包含 build、GenFw、GenFds 等
Conf构建配置目录,存放 target.txt、tools_def.txt、build_rule.txt
Build构建输出目录,按平台与目标生成中间文件与最终镜像

三、编译工具链配置

EDK II 在 Linux 下通常使用 GCC 工具链,在 Windows 下可使用 VS 或 GCC。配置的核心是让 BaseTools 找到编译器,并在 Conf/target.txt 中指定目标平台、架构与工具链标签。

首先编译 BaseTools:

cd edk2
make -C BaseTools
source edksetup.sh

随后编辑 Conf/target.txt,设置关键参数:

ACTIVE_PLATFORM = OvmfPkg/OvmfPkgX64.dsc
TARGET_ARCH    = X64
TOOL_CHAIN_TAG = GCC5
TARGET         = DEBUG
若使用 GCC5 标签,需确保系统已安装 gcc、g++、make、nasm、iasl 与 python3。Ubuntu 下可通过 apt install build-essential nasm uuid-dev python3 acpica-tools 一次性安装。

四、模拟器环境搭建:QEMU + OVMF

模拟器环境是验证模块功能最快的方式。以 OvmfPkgX64 为例,构建完成后会生成 OVMF.fd,可直接由 QEMU 加载运行。

build
qemu-system-x86_64 -bios Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd \
  -drive format=raw,file=fat:rw:./hd \
  -net none -serial stdio

其中 fat:rw:./hd 将宿主机目录映射为虚拟 FAT 盘,便于把编译好的 UEFI 应用放入其中,在 UEFI Shell 下直接执行。这种方式适合验证驱动加载、协议实现与 Shell 应用逻辑。

五、真实平台环境搭建

真实平台通常需要厂商提供的平台包(如 Intel、AMD 或开发板厂商的 EDK II 分支),并配合烧录工具。流程一般为:获取平台包 → 配置 DSC/FDF → 编译生成固件镜像 → 通过 SPI 编程器或厂商工具烧录到主板 Flash → 上电验证。

真实平台与模拟器的差异主要体现在:硬件初始化顺序、内存映射、ACPI 表、Flash 布局与启动设备枚举。模拟器通过的模块,在真机上仍可能因依赖平台特定 PCD 或协议而失败,必须进行真机回归。

六、常见误区与复盘

  • 误区一:直接使用 master 分支。上游变更频繁,容易遇到 BaseTools 与源码不匹配的问题。应优先使用稳定标签。
  • 误区二:忘记执行 git submodule update。部分包依赖子模块,缺失会导致编译报错。
  • 误区三:target.txt 中 TOOL_CHAIN_TAG 与实际安装的编译器不一致,表现为“找不到编译器”或“工具链未定义”。
  • 误区四:模拟器通过即认为真机通过。真机需额外关注 Flash 布局、PCD 配置与平台初始化代码。

建议在环境搭建完成后,先用一个最小 UEFI Application 做冒烟测试:编译、放入虚拟盘、在 UEFI Shell 中执行并打印版本信息。该流程跑通后,再进入具体模块开发,可大幅减少环境类问题的干扰。