4. EDK II 构建系统基础:build命令、target.txt、tools_def.txt、Conf目录、编译流程
EDK II 构建系统是 UEFI 固件开发的基石。理解 build 命令、配置文件体系以及编译流程,是掌握 EDK II 框架的第一步。本章将系统性地拆解构建系统的核心组件,帮助您从“如何编译”深入到“编译如何工作”。
4.1 构建系统全景:Conf 目录与核心配置文件
EDK II 的构建行为由 Conf 目录下的三个核心文本文件控制。在首次运行 edksetup.bat(Windows)或 edksetup.sh(Linux)后,系统会自动从 BaseTools/Conf 模板生成这些文件。
| 配置文件 | 作用域 | 核心作用 |
|---|---|---|
target.txt |
全局构建目标 | 定义目标平台、工具链、架构、编译目标(DEBUG/RELEASE/NOOPT) |
tools_def.txt |
工具链定义 | 声明所有支持的编译器、链接器、汇编器路径及标志 |
build_rule.txt |
文件类型到动作的映射 | 定义如何将 .c/.asm/.vfr 等源文件编译为 .obj/.lib/.efi |
target.txt 和 tools_def.txt 纳入版本管理,但 Conf 目录本身通常不提交,因为它是本地生成环境。
4.2 target.txt:构建目标与策略
target.txt 是构建系统的“总开关”。它定义了构建什么、用什么构建、构建成什么模式。以下是最关键的几个参数:
- ACTIVE_PLATFORM:指定要构建的
.dsc文件路径,例如OvmfPkg/OvmfPkgX64.dsc。 - TARGET:构建目标,可选
DEBUG、RELEASE、NOOPT。DEBUG 包含调试符号,RELEASE 开启优化,NOOPT 关闭优化但保留符号。 - TARGET_ARCH:目标架构,如
X64、IA32、AARCH64。支持多架构用空格分隔。 - TOOL_CHAIN_TAG:工具链标签,如
GCC5、VS2019、CLANG38。必须与tools_def.txt中定义的一致。 - MAX_CONCURRENT_THREAD_NUMBER:并行编译线程数,建议设置为 CPU 核心数,可大幅加速构建。
# target.txt 典型配置片段
ACTIVE_PLATFORM = OvmfPkg/OvmfPkgX64.dsc
TARGET = DEBUG
TARGET_ARCH = X64
TOOL_CHAIN_TAG = GCC5
MAX_CONCURRENT_THREAD_NUMBER = 8
4.3 tools_def.txt:工具链的“字典”
tools_def.txt 是 EDK II 构建系统的工具链数据库。它采用 FAMILY_TAG_TOOLNAME_FLAGS 的命名约定,为每个工具链定义编译器、链接器、汇编器、归档器的路径和标志。
例如,对于 GCC5 工具链的 X64 架构,其 C 编译器定义如下:
# tools_def.txt 片段
*_GCC5_X64_CC_PATH = gcc
*_GCC5_X64_CC_FLAGS = -m64 -g -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -c -include AutoGen.h -DSTRING_ARRAY_NAME=$(BASE_NAME)Strings
target.txt 中设置 TOOL_CHAIN_TAG = GCC5 时,构建系统会自动从 tools_def.txt 中查找所有以 GCC5 开头的定义,组合出完整的编译命令。
4.4 build 命令:构建的入口
build 命令是 EDK II 构建系统的执行入口。它读取 Conf 目录下的配置文件,解析 .dsc、.fdf、.dec 文件,并驱动整个编译流程。
常用命令形式:
# 使用 target.txt 中的默认配置
build
# 指定平台和架构,覆盖 target.txt
build -p OvmfPkg/OvmfPkgX64.dsc -a X64 -t GCC5
# 指定构建目标
build -b RELEASE
# 清理中间文件
build clean
# 清理所有输出(包括最终固件)
build cleanall
# 仅编译指定模块
build -m MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
4.5 编译流程:Pre-Build → Build → Post-Build
EDK II 的编译流程分为三个阶段,每个阶段都有明确的职责。理解这个流程有助于定位构建失败的原因。
4.5.1 Pre-Build:元数据解析与代码生成
Pre-Build 阶段是构建系统的“大脑”。它不编译任何 C 代码,而是执行以下关键任务:
- 解析元数据文件:读取
.dsc(平台描述)、.dec(包声明)、.fdf(固件布局)文件,构建完整的依赖树。 - 生成 AutoGen 文件:为每个模块生成
AutoGen.h和AutoGen.c,包含 GUID、PPI、Protocol 的自动声明。 - 生成 Makefile:根据
build_rule.txt和tools_def.txt,为每个模块生成独立的 Makefile。 - 创建 Build 目录:在
Build/<Platform>/<Target>_<Toolchain>下创建完整的目录结构。
4.5.2 Build:真正的编译与链接
Build 阶段是构建系统的“肌肉”。它调用底层的 make(Linux)或 nmake(Windows)执行实际的编译工作:
- 并行编译:利用
MAX_CONCURRENT_THREAD_NUMBER设置,并行编译所有模块的源文件。 - 模块链接:将编译生成的
.obj文件链接为.efi可执行文件。 - 固件卷生成:将多个
.efi模块打包为 FV(Firmware Volume),并最终生成 FD(Firmware Device)镜像。
tools_def.txt 中的工具链路径是否正确,以及 target.txt 中的 TOOL_CHAIN_TAG 是否与已安装的编译器匹配。
4.5.3 Post-Build:收尾与交付
Post-Build 阶段是构建系统的“包装工”。它执行构建后的处理工作:
| 输出文件 | 说明 |
|---|---|
.efi |
UEFI 可执行文件,可直接在 UEFI Shell 中运行 |
.fv |
固件卷文件,包含多个 .efi 模块的打包镜像 |
.fd |
固件设备文件,最终的 BIOS 镜像文件 |
.map |
符号映射文件,用于调试时地址解析 |
.pdb |
Windows 调试符号文件(仅 VS 工具链) |
4.6 构建目录结构解析
理解构建输出目录的结构,有助于快速定位编译产物和中间文件。
典型构建输出路径:Build/OvmfX64/DEBUG_GCC5/X64/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe/DEBUG/ConPlatformDxe.efi
4.7 构建流程的自动化与定制
EDK II 支持通过 --pcd 参数在构建时动态修改 PCD(Platform Configuration Database)值,无需修改源文件:
# 在构建时覆盖 PCD 值
build -p OvmfPkg/OvmfPkgX64.dsc -a X64 -t GCC5 --pcd gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel=0x80000000
target.txt 中添加自定义 BUILD_OPTIONS 行,将常用的 --pcd 参数固化,避免每次手动输入。
通过本章的学习,您应该能够独立配置 target.txt、理解 tools_def.txt 的作用、熟练使用 build 命令,并清晰描述 EDK II 的三阶段编译流程。这是后续深入学习 UEFI 驱动开发、固件定制和调试的基础。