3. UEFI 开发环境搭建:EDK2 源码获取、VS2019/VS2022 与 GCC 工具链配置、编译第一个 UEFI 应用

搭建稳定、可复现的开发环境是 UEFI 固件开发的基石。本章将引导你完成从源码获取、工具链配置到编译并运行第一个 UEFI 应用程序的完整流程。我们将以 EDK2(EFI Development Kit II)作为核心开发框架,分别讲解在 Windows 与 Linux 环境下的标准配置方法。

3.1 EDK2 源码获取与版本管理

EDK2 是 TianoCore 社区维护的开源 UEFI 固件开发框架,几乎所有的 UEFI BIOS 开发都基于此。推荐使用 Git 进行版本管理,以便跟踪上游更新和自定义修改。

3.1.1 克隆 EDK2 主仓库

打开终端或命令提示符,执行以下命令获取 EDK2 的稳定分支(推荐 edk2-stable202405 或更新版本):

git clone https://github.com/tianocore/edk2.git
cd edk2
git checkout edk2-stable202405

3.1.2 初始化子模块

EDK2 依赖多个子模块(如 MdePkg、CryptoPkg 等),必须同步初始化:

git submodule update --init --recursive
提示: 如果网络不稳定,可尝试使用代理或国内镜像源。子模块同步失败会导致后续编译报错,请务必确认所有子模块均已正确下载。

3.2 Windows 环境:VS2019/VS2022 工具链配置

Windows 平台下,微软 Visual Studio 是编译 EDK2 的主流选择。VS2019 与 VS2022 均受支持,配置步骤基本一致。

3.2.1 安装 Visual Studio

安装时请确保勾选以下工作负载:

  • 使用 C++ 的桌面开发(包含 MSVC 编译器、Windows SDK)
  • Windows 10 SDK 或 Windows 11 SDK(建议最新版本)

3.2.2 配置 EDK2 编译环境

EDK2 使用 edksetup.bat 脚本初始化环境变量。每次打开新终端编译前,需执行:

cd C:\path\to\edk2
edksetup.bat

该脚本会自动检测已安装的 VS 版本并设置 PATH、INCLUDE、LIB 等环境变量。若系统同时安装多个 VS 版本,可通过参数指定:

edksetup.bat --nt32  # 使用 VS2019
edksetup.bat --nt32 VS2022  # 使用 VS2022

3.2.3 验证工具链

执行以下命令确认编译器可用:

build -p MdePkg\MdePkg.dsc -a X64 -t VS2022 -b DEBUG

若输出无错误,则表明工具链配置成功。

3.3 Linux 环境:GCC 工具链配置

Linux 平台通常使用 GCC 交叉编译器。以 Ubuntu 22.04 LTS 为例:

3.3.1 安装必要软件包

sudo apt update
sudo apt install build-essential uuid-dev nasm python3 python3-pip

3.3.2 安装 GCC 交叉编译器

EDK2 需要 gcc-aarch64-linux-gnu(ARM64)或 gcc-x86-64-linux-gnu(X64)。以 X64 目标为例:

sudo apt install gcc-x86-64-linux-gnu

3.3.3 配置 EDK2 环境

Linux 下使用 edksetup.sh:

cd ~/edk2
source edksetup.sh

该脚本会设置 WORKSPACE、PACKAGES_PATH 等环境变量。建议将 source edksetup.sh 添加到 ~/.bashrc 中以便自动加载。

3.3.4 验证 GCC 工具链

build -p MdePkg\MdePkg.dsc -a X64 -t GCC5 -b DEBUG
注意: EDK2 中 GCC 工具链标签通常为 GCC5(兼容 GCC 5.x 及以上版本)。若使用 Clang,请使用 CLANGDWARF 或 CLANGPDB 标签。

3.4 工具链对比与选择建议

特性 VS2019/VS2022 GCC (Linux) GCC (Windows, MinGW)
调试体验 优秀(集成 WinDbg) 良好(GDB) 一般
编译速度 较快 中等 较慢
二进制兼容性 PE32+ 格式 PE32+ 格式 PE32+ 格式
社区支持 广泛 广泛 较少
推荐场景 Windows 原生开发 Linux 服务器/CI 跨平台测试

3.5 编译第一个 UEFI 应用:HelloWorld

EDK2 自带一个经典的 HelloWorld 示例,位于 MdeModulePkg/Application/HelloWorld。我们将以此为例,完成从编译到运行的完整流程。

3.5.1 确认应用源码结构

进入 MdeModulePkg/Application/HelloWorld 目录,查看关键文件:

  • HelloWorld.c — 主程序源码
  • HelloWorld.inf — 模块描述文件(INF),定义模块属性、依赖库、源文件等

HelloWorld.c 核心代码:

#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>

EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  Print(L"Hello, UEFI World!\n");
  return EFI_SUCCESS;
}

3.5.2 修改平台描述文件(DSC)

为了让 EDK2 的构建系统识别并编译该应用,需要将其添加到平台描述文件(.dsc)中。以 MdeModulePkg/MdeModulePkg.dsc 为例,在 [Components] 段添加:

[Components]
  MdeModulePkg/Application/HelloWorld/HelloWorld.inf
关键概念: DSC 文件定义了整个平台的组件列表、库实例、PCD 设置等。任何新增模块都必须在此注册。

3.5.3 执行编译

在 EDK2 根目录执行以下命令(以 VS2022 为例):

build -p MdeModulePkg\MdeModulePkg.dsc -a X64 -t VS2022 -b DEBUG

编译成功后,输出文件位于 Build/MdeModule/DEBUG_VS2022/X64/HelloWorld.efi。

3.5.4 在模拟器中运行

EDK2 提供了 NT32 模拟器,可在 Windows 下直接运行 UEFI 应用:

build -p MdeModulePkg\MdeModulePkg.dsc -a X64 -t VS2022 -b DEBUG
cd Build\MdeModule\DEBUG_VS2022\X64
SecMain.efi

在模拟器 Shell 中,切换到 fs0: 并执行 HelloWorld.efi,即可看到输出:

FS0:\> HelloWorld.efi
Hello, UEFI World!

3.6 编译流程与关键概念图解

下图展示了从源码到 UEFI 可执行文件的完整编译流程:

EDK2 编译流程与关键组件 C 源码 (.c) INF 描述文件 DSC 平台文件 FDF 布局文件 EDK2 Build 引擎 (build 命令) 解析 INF → 生成 Makefile → 调用编译器/链接器 中间文件 (.obj, .lib, .map) COFF 目标文件 + 静态库 GenFw / 链接器 生成 PE32+ 格式 UEFI 镜像 HelloWorld.efi 输出路径:Build/<Platform>/DEBUG_<Toolchain>/<Arch>/

3.7 常见问题与排查

  • 编译报错:找不到头文件 — 检查 PACKAGES_PATH 环境变量是否指向 EDK2 根目录,或子模块是否未同步。
  • 链接错误:未解析的外部符号 — 确认 HelloWorld.inf 的 [LibraryClasses] 段已包含 UefiLib、UefiApplicationEntryPoint 等必要库。
  • 模拟器无法启动 — 确保以管理员权限运行 SecMain.efi,或检查 Windows 防火墙是否阻止了模拟器进程。
  • GCC 编译报错:缺少 nasm — 安装 NASM 汇编器:sudo apt install nasm。

3.8 小结

至此,你已经完成了 UEFI 开发环境的完整搭建,并成功编译并运行了第一个 UEFI 应用程序。掌握 EDK2 的构建系统、工具链配置和基本调试方法,是后续深入学习 UEFI 驱动开发、固件定制和平台初始化的基础。建议将本章的编译流程反复练习,直至能够独立完成从零开始的环境搭建。