Build过程

edk2build分为三个阶段:

1、Pre-build或者AutoGen:

2、Build或$(MAKE)

3、Post-build或imageGen阶段

uefi win7 镜像_固件

Pre-build

        该流程主要工作为解析元数据文件、UCS-2LE编码文件和VFR文件,来生成一些C源码(AutoGen.c、AutoGen.h)和Makefile。

AutoGen

        AutoGen主要包括以下功能和用途:

  1. 生成Pcd(Platform Configuration Database)值:Pcd是一种用于配置和控制UEFI固件的机制。AutoGen.c 会生成一些代码来定义和初始化Pcd变量,这些变量的值可以在 .dsc 文件中进行配置。
  2. 生成模块依赖关系AutoGen.c 会生成模块之间的依赖关系,以确保在构建过程中正确地处理模块的编译和链接顺序。
  3. 生成模块入口点:对于可执行的模块,AutoGen.c 会生成入口点函数,用于启动模块的执行。这通常是UEFI固件中可执行模块的入口函数。
  4. 生成其他配置信息:根据 .fdf 文件中的描述,AutoGen.c 可能还会生成其他配置信息,如Flash区域的描述、UEFI固件的映像布局等。

        总之,AutoGen 是一个由EDK2自动生成的辅助代码文件,它包含了UEFI固件的配置和构建信息。这些信息在构建过程中用于生成UEFI固件映像,确保固件在不同平台上能够正确运行。

        build工具在AutoGen阶段找的第一个文件就是$(WORKSPACE)/Conf目录下的target.txt,该文件是默认配置,而文件内的内容是可以被build工具的命令行选项覆盖的。

    一旦build工具知道了要构建的内容以及如何构建,就会开始解析DSC文件,而在DSC文件中build工具就能找到所有模块和库的INF文件。并通过这种方式,build工具就能解析构成平台的所有模块和包。

    AutoGen阶段做的下一件事就是生成构建模块所需的文件(AutoGen.c、AutoGen.h、.depex、Makefile),且在DSC文件中找到的每个模块都会为它生成一个makefile,一旦生成了所有模块的makefile,build工具就会为每个模块的makefile调用make命令。

uefi win7 镜像_linux_02

uefi win7 镜像_uefi win7 镜像_03

Build

        从平台角度看,Build阶段完成的工作包括构建库模块,构建非库模块,最后(如果期望的输出是要刻录到物理平台上的flash部件中的文件)生成flash映像。

uefi win7 镜像_驱动程序_04

        从模块的角度来看,Build阶段完成的工作包括预处理、编译或组装、静态/动态链接和模块映像生成。

uefi win7 镜像_linux_05

        该阶段处理源码文件来创建PE32/PE32+/COFF映像,使用NMAKE或MAKE将这些映像处理为EFI格式,而Makefile则指定了编译器、链接器、汇编程序和GenFw工具命令和选项。

        值得注意的是,如果dsc文件中并没有指定FDF文件,那么build在此处终止,并不会执行后面的Post-build,生成单独的模块EFI镜像。

        在该阶段会生成的一些文件后缀如下表所示:

uefi win7 镜像_linux_06

uefi win7 镜像_linux_07

Preprocess/Trim(预处理阶段)

        预处理做的就一件事,进行宏替换,头文件中定义的宏,需要通过预处理进行宏替换。

        Trim的作用则是针对预处理的汇编文件、VFR文件和.dxs文件,需要额外的Trim步骤来删除预处理器留下的不必要的内容。

Compile/Assembled(编译)

        一句话,将c文件编译生成.obj文件。

Static/Dynamic(静态链接/动态链接)

        静态:对于有c文件的库模块,利用静态链接将obj文件链接上静态库,对于没有c文件的模块,直接跳。

        动态:作用于非库模块,在静态链接步骤中生成的静态库文件将与依赖库模块生成的其他静态库文件一起链接到.dll文件中。

Generate Module Images(生成模块映像)

        构建模块生成的最终映像是EFI/Framework协议可以识别的文件。默认支持的文件类型为EFI可执行映像文件(. EFI), ACPI机器语言文件(.aml), ACPI表文件(. ACPI),实模式可执行文件(.com)和微码二进制文件(.bin)。

        通过GenFw将前面生成的.dll文件转换为.efi文件。(GenFw工具用于从第三方工具链生成的PE/PE32+/COFF镜像中,根据INF文件中列出的组件或模块类型生成UEFI固件镜像文件,即.efi文件。)

Post-build

        该阶段获取二进制EFI格式文件,利用GenFds创建EFI FLASH镜像,EFI更新胶囊,UEFI应用或者PCI Option ROMs。这个阶段会基于FDF文件处理单个的efi文件,将他们的格式转化为EFI_SECTION类型,并使用规则将他们组合成不同的FFS、FV、FD。

        该阶段会生成的一些文件后缀如下表所示:

uefi win7 镜像_linux_08

         根据上表可以看到,从Build阶段生成了.efi文件,那么Post-build阶段就是将这些.efi文件进行一系列转换最后成.fd文件。下面是一些用到的工具:

GenSec

        GenSec(Generate Section)用于生成文件section信息的工具。文件section是指可执行文件(如EFI应用程序或驱动程序)中的一个逻辑部分,通常包含代码、数据、头部和其他元数据。

GenFfs

        GenFfs(Generate Firmware File System)用于生成FFS(Firmware File System)文件。FFS文件是一种UEFI固件中用于组织和存储固件模块(如UEFI应用程序、驱动程序和固件升级文件)的容器。GenFfs工具的主要功能是创建这些FFS文件。

GenVtf

        这个工具是为IA32 X64和IPF映像生成引导带文件(又名卷顶文件,或VTF)。

GenFv

        GenFv(Generate Firmware Volume)用于创建UEFI固件中的Firmware Volume(FV)文件。FV文件是一种容器,用于存储和组织UEFI固件中的各种固件模块(如EFI应用程序、驱动程序、固件升级文件等)。GenFv工具的主要功能是将这些固件模块组织到FV文件中,以便将其嵌入到UEFI固件中。

GenFds

       GenFds(Generate Firmware Descriptor)用于生成描述固件映像的描述符文件(通常具有.fd扩展名)。这些描述符文件包含有关UEFI固件映像的信息,包括Firmware Volume(FV)的信息、Firmware File System(FFS)文件的信息以及其他与UEFI固件相关的元数据。

Image

        Image指的是映像文件,一般指可执行的二进制文件或固件文件。

uefi win7 镜像_linux_09

生成FFS文件

  • a. GenFfs工具: 生成的TE格式文件通常会被打包成FFS文件。GenFfs工具是用于这一目的的工具之一。GenFfs工具会读取一个FDF文件(Flash Description File),该文件描述了FFS文件的组织结构和内容。
  • b. FFS容器: GenFfs工具将TE文件打包到FFS容器中,为每个FFS文件创建一个FFS标头。FFS标头包含有关FFS文件的元数据,例如文件类型、大小和属性。

生成FV文件 

  • a. GenFv工具: 在构建过程的某个阶段,通常是在post-build阶段的后期,使用GenFv工具或类似的工具来创建FV(Firmware Volume)文件。FV文件是一种UEFI特定的容器,可以包含一个或多个FFS文件。
  • b. FV标头: GenFv工具为FV文件添加一个FV标头,其中包含有关FV的元数据,如文件系统信息、校验和等。

生成FD文件 

       GenFds(Generate Firmware Descriptor)工具是EDK II的一部分,用于生成Firmware Volume(FV)描述符文件,其中包含有关UEFI固件中包含的FV的信息。这些描述符文件通常具有.fd文件扩展名。可以使用GenFds工具创建描述符文件,其中包含一个或多个FV的信息。这对于将多个FV嵌入到UEFI固件中非常有用。

FD、FV、FFS

        UEFI中的FD(Firmware Device)、FV(Firmware Volume)和FFS(Firmware File System)可以被看作是一种层次结构,类似于树状图的结构,其中FD是根,FV是树的分支,而FFS是树的叶子。这种层次结构有助于组织和管理UEFI固件中的各种数据和文件。

uefi win7 镜像_固件_10

 

uefi win7 镜像_1024程序员节_11

        在UEFI中,FD、FV和FFS是固件开发中常见的概念,它们分别表示固件设备(Firmware Device)、固件卷(Firmware Volume)和固件文件系统(Firmware File System)。它们之间有以下区别和联系:

  1. FD(Firmware Device):FD是UEFI固件的最高级别概念,它代表了整个固件设备,包括固件芯片或存储器。FD文件是UEFI固件的核心部分,包含了引导程序、驱动程序和其他必要的固件组件。FD文件是UEFI固件的主要执行部分,负责启动和初始化硬件设备。
  2. FV(Firmware Volume):FV是UEFI固件中的一种数据结构,用于组织和存储固件的各个部分。一个FV可以包含多个模块(Module),每个模块可以是一个驱动程序、一个应用程序或其他固件组件。FV文件相当于UEFI固件的存储空间,它通过GUID(全局唯一标识符)来标识和访问其中的模块。
  3. FFS(Firmware File System):FFS是UEFI固件中的一种文件系统,用于组织和管理固件中的文件。FFS由一个或多个文件组成,每个文件都有唯一的GUID标识符。FFS文件可以存储各种类型的数据,包括驱动程序、配置文件、固件升级文件等。FFS文件系统是FV中的一个重要组成部分,它提供了对固件中文件的访问和管理功能。

区别和联系:

  • FD是UEFI固件的最高级别概念,代表整个固件设备;FV是UEFI固件中的数据结构,用于组织和存储固件的各个部分;FFS是UEFI固件中的文件系统,用于组织和管理固件中的文件。
  • FD文件是UEFI固件的核心部分,包含引导程序、驱动程序等;FV文件是UEFI固件的存储空间,包含多个模块;FFS文件是FV中的一个重要组成部分,用于存储各种类型的数据。
  • FD文件包含了FV文件;FV文件包含了FFS文件;FFS文件存储在FV文件中。它们之间存在依赖关系,共同构成了UEFI固件的结构和功能。

FD与FV

在UEFI中,FD(Firmware Device)和FV(Firmware Volume)之间存在着一种父子关系。

        FD文件是UEFI固件的核心部分,它包含了UEFI固件的引导程序、驱动程序和其他必要的固件组件。FD文件会将FV文件加载到内存中,并通过FV文件中的模块来执行相应的功能。

        FV文件是UEFI固件中的一种数据结构,用于组织和存储固件的各个部分。一个FD可以包含多个FV,每个FV可以包含多个模块。FV文件通过GUID(全局唯一标识符)来标识和访问其中的模块。

        因此,可以说FV文件是FD文件中存储固件组件的一种方式,FD文件通过加载FV文件来实现固件的功能。FD和FV之间的关系可以理解为父子关系,FD是FV的上层容器,FV是FD中存储固件组件的一种结构。

FV与FFS

        FFS虽然是一个文件系统,但是它并没有层次结构,所有的固件文件都一字排开,组成固件文件系统。这种结构也就导致,查询某一个固件文件只能够遍历。

uefi win7 镜像_uefi win7 镜像_12

FFS Header

        FFS的头包含了部分属性,Name、Type、State、Size

uefi win7 镜像_uefi win7 镜像_13

 Section Header

        Section的头包含了Section的Type与Length

uefi win7 镜像_uefi win7 镜像_14

Section与efi  

        在UEFI(统一可扩展固件接口)中,"section"(节)是一个术语,通常指的是可执行二进制文件(例如`.efi`文件)中的逻辑分块或段。每个节包含了特定类型的数据或代码,用于实现特定的功能。这些节被组合在一起构成一个完整的可执行文件。

        一个EFI可执行文件(例如`.efi`文件)通常包含多个节,每个节有其特定的功能和数据。以下是一些常见的EFI可执行文件中可能包含的节:

1. 代码节(Code Section):这些节包含可执行代码,用于执行特定的任务。例如,一个EFI引导加载程序的代码节包含引导加载程序的实际执行代码。

2. 数据节(Data Section):这些节包含各种数据,如全局变量、常量数据等。数据节可以存储用于在程序执行过程中读取或修改的数据。

3. 引导信息节(Boot Information Section):这些节包含关于EFI映像的元数据和信息,如映像的版本、作者、创建日期等。这些信息通常不是必需的,但可以用于描述EFI映像的属性。

4. 调试信息节(Debug Information Section):这些节包含用于调试的信息,例如源代码行号和变量名的映射。调试信息节对于开发人员在调试EFI映像时非常有用。

5. 导出节(Export Section):这些节包含了EFI映像提供给其他EFI模块或应用程序使用的接口信息。这些接口可以被其他模块引用,以实现模块间的通信和交互。

        这些节的组合构成了一个完整的EFI可执行文件。每个节都有其自己的特定用途,它们共同协作以实现EFI应用程序或驱动程序的功能。EFI标准规定了EFI可执行文件的格式和节的结构,以确保它们在UEFI环境中能够正确加载和执行。所以,"section" 是EFI可执行文件中的逻辑组成部分,用于实现不同的功能。

Section

        Section有很多种类型,但是总的来说其实就两种:封装节(En)、叶子节(Ln),而一个固件文件中的Section分布可以如下图,可以既有封装节,也可以有叶子节,而封装节类似于父节,它可以包含作为子节的封装节与叶子节。

uefi win7 镜像_linux_15

uefi win7 镜像_驱动程序_16

 VTF

        卷顶文件(VTF)是必须定位的文件,该文件的最后一个字节也是固件卷的最后一个字节。VTF的文件名GUID为EFI_FFS_VOLUME_TOP_FILE_GUID,固件文件系统驱动程序代码必须知道这个GUID,并根据需要插入一个pad文件,以保证在写入和更新操作时VTF正确地位于固件卷的顶部。文件长度和对齐要求必须与卷顶一致。否则,写错误,不修改固件卷。

FDF

        FDF文件用于描述固件在flash中的布局和位置,这些固件是与UEFI兼容的二进制镜像,一般来说,生成固件的源码中只有一个FDF文件,其作用是规定把哪些包编入flash中,并确定编入的位置,FDF文件由[Defines]、[FD]、[FV]、[Capsule]、[VTF]、[Rule]、[OptionRom]组成。下面以edk2下的EmulatorPkg下的EmulatorPkg.fdf文件为例。

[FD]

定义:在FDF(Firmware Description File)中,[FD] 部分用于描述固件设备(Firmware Device)的参数和配置

参数:

  1. BaseAddress = 0x102000000|gEmulatorPkgTokenSpaceGuid.PcdEmuFdBaseAddress:这里指定了 FD 的基地址。基地址是 FD 在内存中的起始物理地址。在这个示例中,基地址被设置为 0x102000000,并且还引用了一个 PCD(Platform Configuration Database)标记 gEmulatorPkgTokenSpaceGuid.PcdEmuFdBaseAddress,该标记可能用于在不同的构建配置中动态设置基地址。
  2. Size = 0x005a0000|gEmulatorPkgTokenSpaceGuid.PcdEmuFirmwareFdSize:这是指定 FD 的大小。大小表示 FD 占用的字节数。在这个示例中,大小被设置为 0x005a0000,并且也引用了一个 PCD 标记 gEmulatorPkgTokenSpaceGuid.PcdEmuFirmwareFdSize,用于可能的动态配置。
  3. ErasePolarity = 1:这是关于擦除极性的设置,指定了在擦除闪存区域时设置或擦除位的方式。在这里,它被设置为 1。
  4. BlockSize = 0x10000:这是指定 FD 的块大小,块是闪存区域的基本擦除单元。在这个示例中,块大小被设置为 0x10000,表示每个块的大小为 64KB。
  5. NumBlocks = 0x5a:这是指定 FD 中块的数量。在这个示例中,块的数量被设置为 0x5a,表示 FD 中有 90 个块。
[FD.Fv_Recovery]
#
# In OS X PEIMs are really XIP, so we need to make this address match the malloced
# buffer for the FD (0x41000000). If this address does not match the FV will get
# relocated in place (works, but not a great idea).
#
BaseAddress   = 0x102000000|gEmulatorPkgTokenSpaceGuid.PcdEmuFdBaseAddress   #The base address of the FLASH Device.
Size          = 0x005a0000|gEmulatorPkgTokenSpaceGuid.PcdEmuFirmwareFdSize  #The size in bytes of the FLASH Device
ErasePolarity = 1
BlockSize     = 0x10000
NumBlocks     = 0x5a

0x00000000|0x00580000
gEmulatorPkgTokenSpaceGuid.PcdEmuFlashFvRecoveryBase|gEmulatorPkgTokenSpaceGuid.PcdEmuFlashFvRecoverySize
FV = FvRecovery

0x00580000|0x0000c000
gEmulatorPkgTokenSpaceGuid.PcdEmuFlashNvStorageVariableBase|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
#NV_VARIABLE_STORE
DATA = {
  ## This is the EFI_FIRMWARE_VOLUME_HEADER
  # ZeroVector []
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  # FileSystemGuid: gEfiSystemNvDataFvGuid         =
  #  { 0xFFF12B8D, 0x7696, 0x4C8B, { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
  0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C,
  0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50,
  # FvLength: 0x20000
  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
  # Signature "_FVH"       #Attributes
  0x5f, 0x46, 0x56, 0x48, 0xff, 0xfe, 0x04, 0x00,
  # HeaderLength #CheckSum #ExtHeaderOffset #Reserved #Revision
  0x48, 0x00, 0x36, 0x09, 0x00, 0x00, 0x00, 0x02,
  # Blockmap[0]: 2 Blocks * 0x10000 Bytes / Block
  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
  # Blockmap[1]: End
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  ## This is the VARIABLE_STORE_HEADER
!if $(SECURE_BOOT_ENABLE) == FALSE
  #Signature: gEfiVariableGuid =
  #  { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d }}
  0x16, 0x36, 0xcf, 0xdd, 0x75, 0x32, 0x64, 0x41,
  0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d,
!else
  # Signature: gEfiAuthenticatedVariableGuid =
  #  { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 }}
  0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43,
  0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92,
!endif
  #Size: 0xc000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) - 0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0xBFB8
  # This can speed up the Variable Dispatch a bit.
  0xB8, 0xBF, 0x00, 0x00,
  #FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32
  0x5A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}

0x0058c000|0x00002000
#NV_EVENT_LOG
gEmulatorPkgTokenSpaceGuid.PcdEmuFlashNvStorageEventLogBase|gEmulatorPkgTokenSpaceGuid.PcdEmuFlashNvStorageEventLogSize

0x0058e000|0x00002000
gEmulatorPkgTokenSpaceGuid.PcdEmuFlashNvStorageFtwWorkingBase|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
#NV_FTW_WORKING
DATA = {
  # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid         =
  #  { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65,  0x0, 0xfd, 0x9f, 0x1b, 0x95 }}
  0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49,
  0xa0, 0xce, 0x65,  0x0, 0xfd, 0x9f, 0x1b, 0x95,
  # Crc:UINT32            #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved
  0xE2, 0x33, 0xF2, 0x03, 0xFE, 0xFF, 0xFF, 0xFF,
  # WriteQueueSize: UINT64
  0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}

0x00590000|0x00010000
#NV_FTW_SPARE
gEmulatorPkgTokenSpaceGuid.PcdEmuFlashNvStorageFtwSpareBase|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize

[FV]

定义:在FDF(Firmware Description File)中,[FV] 部分用于描述固件卷(Firmware Volume)的参数和配置。

参数:

  1. FvNameGuid = 6D99E806-3D38-42c2-A095-5F4300BFD7DC:这里指定了 FV 的名称或标识符,使用 GUID(全局唯一标识符)来唯一标识 FV。
  2. FvAlignment = 16:这是 FV 的对齐方式,它指定 FV 在内存中的对齐要求。在这个示例中,FV 被要求以 16 字节的边界对齐。
  3. ERASE_POLARITY = 1:这是擦除极性的设置,它通常用于描述如何在擦除闪存区域时设置或擦除位。在这里,它被设置为 1。
  4. MEMORY_MAPPED = TRUE:这指定了 FV 是否是内存映射型的。如果设置为 TRUE,表示 FV 是通过内存映射方式访问的。
  5. STICKY_WRITE = TRUE:这表示是否启用了“粘性写入”特性。粘性写入通常用于描述写入数据后是否会自动保留在闪存中。
  6. LOCK_CAP = TRUELOCK_STATUS = TRUE:这些参数描述了是否支持闪存区域的锁定功能以及锁定状态。如果 LOCK_CAP 设置为 TRUE,表示支持锁定;LOCK_STATUS 设置为 TRUE,则表示锁定状态已经处于启用状态。
  7. WRITE_DISABLED_CAP = TRUEWRITE_ENABLED_CAP = TRUEWRITE_STATUS = TRUEWRITE_LOCK_CAP = TRUEWRITE_LOCK_STATUS = TRUE:这些参数描述了闪存区域的写入功能,包括是否支持写入禁用和启用,以及写入状态和写入锁定的能力和状态。
  8. READ_DISABLED_CAP = TRUEREAD_ENABLED_CAP = TRUEREAD_STATUS = TRUEREAD_LOCK_CAP = TRUEREAD_LOCK_STATUS = TRUE:类似于写入功能,这些参数描述了闪存区域的读取功能,包括是否支持读取禁用和启用,以及读取状态和读取锁定的能力和状态。
[FV.FvRecovery]
FvNameGuid         = 6D99E806-3D38-42c2-A095-5F4300BFD7DC
FvAlignment        = 16         #FV alignment and FV attributes setting.
ERASE_POLARITY     = 1
MEMORY_MAPPED      = TRUE
STICKY_WRITE       = TRUE
LOCK_CAP           = TRUE
LOCK_STATUS        = TRUE
WRITE_DISABLED_CAP = TRUE
WRITE_ENABLED_CAP  = TRUE
WRITE_STATUS       = TRUE
WRITE_LOCK_CAP     = TRUE
WRITE_LOCK_STATUS  = TRUE
READ_DISABLED_CAP  = TRUE
READ_ENABLED_CAP   = TRUE
READ_STATUS        = TRUE
READ_LOCK_CAP      = TRUE
READ_LOCK_STATUS   = TRUE

#
#  PEI Phase modules
#

#
#  PEI Apriori file example, more PEIM module added later.
#
APRIORI PEI {
  INF  MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf
  INF  MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
  INF  MdeModulePkg/Universal/PCD/Pei/Pcd.inf
  }
APRIORI DXE {
  INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
  INF  MdeModulePkg/Universal/Metronome/Metronome.inf
  }
INF  EmulatorPkg/Sec/Sec.inf
INF  MdeModulePkg/Core/Pei/PeiMain.inf
INF  MdeModulePkg/Universal/PCD/Pei/Pcd.inf
INF  MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf
INF  MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
INF  EmulatorPkg/BootModePei/BootModePei.inf
INF  EmulatorPkg/AutoScanPei/AutoScanPei.inf
INF  EmulatorPkg/FirmwareVolumePei/FirmwareVolumePei.inf
INF  EmulatorPkg/FlashMapPei/FlashMapPei.inf
INF  EmulatorPkg/ThunkPpiToProtocolPei/ThunkPpiToProtocolPei.inf
INF  MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
INF  MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
INF  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf

#
#  DXE Phase modules
#
INF  MdeModulePkg/Core/Dxe/DxeMain.inf
INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
INF  MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
INF  MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
INF  MdeModulePkg/Universal/Metronome/Metronome.inf
INF  EmulatorPkg/RealTimeClockRuntimeDxe/RealTimeClock.inf
INF  EmulatorPkg/ResetRuntimeDxe/Reset.inf
INF  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
INF  EmulatorPkg/FvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
INF  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
INF  MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
INF  EmulatorPkg/EmuThunkDxe/EmuThunk.inf
INF  EmulatorPkg/CpuRuntimeDxe/Cpu.inf
INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
INF  EmulatorPkg/PlatformSmbiosDxe/PlatformSmbiosDxe.inf
INF  EmulatorPkg/TimerDxe/Timer.inf
INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
INF  MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
INF  MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
INF  MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
INF  MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
INF  MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
INF  MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf

INF  MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
INF  MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
INF  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
INF  MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
INF  MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
INF  MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
INF  MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
INF  MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
INF  MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
INF  MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf

INF  EmulatorPkg/EmuBusDriverDxe/EmuBusDriverDxe.inf
INF  EmulatorPkg/EmuGopDxe/EmuGopDxe.inf
INF  EmulatorPkg/EmuSimpleFileSystemDxe/EmuSimpleFileSystemDxe.inf
INF  EmulatorPkg/EmuBlockIoDxe/EmuBlockIoDxe.inf
INF  EmulatorPkg/EmuSnpDxe/EmuSnpDxe.inf

INF  MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
INF  MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
INF  MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
INF  MdeModulePkg/Universal/PrintDxe/PrintDxe.inf
INF  MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
!if "XCODE5" not in $(TOOL_CHAIN_TAG)
INF  MdeModulePkg/Logo/LogoDxe.inf
!endif
INF  MdeModulePkg/Universal/LoadFileOnFv2/LoadFileOnFv2.inf
INF  RuleOverride = UI MdeModulePkg/Application/UiApp/UiApp.inf
INF  MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf
INF  MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf

#
# Secure Boot Key Enroll
#
!if $(SECURE_BOOT_ENABLE) == TRUE
INF SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
!endif

#
# Network stack drivers
#
!if $(NETWORK_SUPPORT)
INF  EmulatorPkg/EmuSnpDxe/EmuSnpDxe.inf
!endif
!include NetworkPkg/Network.fdf.inc

#
# EFI Redfish drivers
#
!include RedfishPkg/Redfish.fdf.inc

INF FatPkg/EnhancedFatDxe/Fat.inf

!if "XCODE5" not in $(TOOL_CHAIN_TAG)
INF  ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf
!endif
INF  ShellPkg/Application/Shell/Shell.inf

更详细的 【UEFI基础】FDF文件_uefi fdf 文件_jiangwei0512的博客-CSDN博客

 Build实践

         通过在edk2下直接执行build命令,观察终端打印的信息。

         对打印信息进行截取并分析,可以观察到和前面提到的Build过程大致吻合,对应了之前的Pre-build阶段和Build阶段,最终生成了一个uefi应用程序(.efi文件)。

"gcc-ar" cr /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/MdePkg/Library/BaseLib/BaseLib/OUTPUT/BaseLib.lib  @/home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/MdePkg/Library/BaseLib/BaseLib/OUTPUT/object_files.lst
"gcc" -MMD -MF /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/AutoGen.obj.deps -g -Os -fshort-wchar -fno-builtin -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -include AutoGen.h -fno-common -ffunction-sections -fdata-sections -DSTRING_ARRAY_NAME=Uefi_Main_lyStrings -m64 -fno-stack-protector "-DEFIAPI=__attribute__((ms_abi))" -maccumulate-outgoing-args -mno-red-zone -Wno-address -mcmodel=small -fpie -fno-asynchronous-unwind-tables -Wno-address -fno-omit-frame-pointer -flto -DUSING_LTO -nostdinc -nostdlib -DUEFI_C_SOURCE -c -o /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/./AutoGen.obj -I/home/luying/uefi_workspace/edk2/lywhPkg/Applications/Uefi_Main -I/home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG -I/home/luying/uefi_workspace/edk2/MdePkg -I/home/luying/uefi_workspace/edk2/MdePkg/Include -I/home/luying/uefi_workspace/edk2/MdePkg/Test/UnitTest/Include -I/home/luying/uefi_workspace/edk2/MdePkg/Test/Mock/Include -I/home/luying/uefi_workspace/edk2/MdePkg/Library/MipiSysTLib/mipisyst/library/include -I/home/luying/uefi_workspace/edk2/MdePkg/Include/X64 -I/home/luying/uefi_workspace/edk2/MdeModulePkg -I/home/luying/uefi_workspace/edk2/MdeModulePkg/Include -I/home/luying/uefi_workspace/edk2/MdeModulePkg/Test/Mock/Include /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/AutoGen.c
"gcc" -MMD -MF /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/Uefi_Main_ly.obj.deps -g -Os -fshort-wchar -fno-builtin -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -include AutoGen.h -fno-common -ffunction-sections -fdata-sections -DSTRING_ARRAY_NAME=Uefi_Main_lyStrings -m64 -fno-stack-protector "-DEFIAPI=__attribute__((ms_abi))" -maccumulate-outgoing-args -mno-red-zone -Wno-address -mcmodel=small -fpie -fno-asynchronous-unwind-tables -Wno-address -fno-omit-frame-pointer -flto -DUSING_LTO -nostdinc -nostdlib -DUEFI_C_SOURCE -c -o /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/./Uefi_Main_ly.obj -I/home/luying/uefi_workspace/edk2/lywhPkg/Applications/Uefi_Main -I/home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG -I/home/luying/uefi_workspace/edk2/MdePkg -I/home/luying/uefi_workspace/edk2/MdePkg/Include -I/home/luying/uefi_workspace/edk2/MdePkg/Test/UnitTest/Include -I/home/luying/uefi_workspace/edk2/MdePkg/Test/Mock/Include -I/home/luying/uefi_workspace/edk2/MdePkg/Library/MipiSysTLib/mipisyst/library/include -I/home/luying/uefi_workspace/edk2/MdePkg/Include/X64 -I/home/luying/uefi_workspace/edk2/MdeModulePkg -I/home/luying/uefi_workspace/edk2/MdeModulePkg/Include -I/home/luying/uefi_workspace/edk2/MdeModulePkg/Test/Mock/Include /home/luying/uefi_workspace/edk2/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly.c
rm -f /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/Uefi_Main_ly.lib
"gcc-ar" cr /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/Uefi_Main_ly.lib  @/home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/object_files.lst
"gcc" -o /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/Uefi_Main_ly.dll -nostdlib -Wl,-n,-q,--gc-sections -z common-page-size=0x40 -Wl,--entry,_ModuleEntryPoint -u _ModuleEntryPoint -Wl,-Map,/home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/Uefi_Main_ly.map,--whole-archive -Wl,-melf_x86_64,--oformat=elf64-x86-64,-pie -flto -Os -Wl,--start-group,@/home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/static_library_files.lst,--end-group -g -Os -fshort-wchar -fno-builtin -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -include AutoGen.h -fno-common -ffunction-sections -fdata-sections -DSTRING_ARRAY_NAME=Uefi_Main_lyStrings -m64 -fno-stack-protector "-DEFIAPI=__attribute__((ms_abi))" -maccumulate-outgoing-args -mno-red-zone -Wno-address -mcmodel=small -fpie -fno-asynchronous-unwind-tables -Wno-address -fno-omit-frame-pointer -flto -DUSING_LTO -nostdinc -nostdlib -DUEFI_C_SOURCE -Wl,--defsym=PECOFF_HEADER_SIZE=0x228 -Wl,--script=/home/luying/uefi_workspace/edk2/BaseTools/Scripts/GccBase.lds -Wno-error
"objcopy"  /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/Uefi_Main_ly.dll
cp -p -f /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/Uefi_Main_ly.dll /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/Uefi_Main_ly.debug
"objcopy" --strip-unneeded -R .eh_frame /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/Uefi_Main_ly.dll
"objcopy" --add-gnu-debuglink="/home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/Uefi_Main_ly.debug" /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/Uefi_Main_ly.dll
cp -p -f /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/Uefi_Main_ly.debug /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/Uefi_Main_ly.debug
"GenFw" -e UEFI_APPLICATION -o /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/Uefi_Main_ly.efi /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/Uefi_Main_ly.dll
cp -p -f /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/Uefi_Main_ly.efi /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG
cp -p -f /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/Uefi_Main_ly.efi /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/Uefi_Main_ly.efi
cp -p -f /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/*.map /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT
#这个命令的作用是使用 gcc-ar 工具创建一个名为 BaseLib.lib 的静态库文件,
#该库文件将包含列表中 object_files.lst 中列出的目标文件。
#静态库文件通常用于将多个目标文件打包到一个单独的库中,
#以便在链接时将它们链接到应用程序中。
"gcc-ar" cr /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/MdePkg/Library/BaseLib/BaseLib/OUTPUT/BaseLib.lib  @/home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/MdePkg/Library/BaseLib/BaseLib/OUTPUT/object_files.lst
#将AutoGen.c编译为AutoGen.obj
"gcc" -MMD -MF /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/AutoGen.obj.deps -g -Os -fshort-wchar -fno-builtin -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -include AutoGen.h -fno-common -ffunction-sections -fdata-sections -DSTRING_ARRAY_NAME=Uefi_Main_lyStrings -m64 -fno-stack-protector "-DEFIAPI=__attribute__((ms_abi))" -maccumulate-outgoing-args -mno-red-zone -Wno-address -mcmodel=small -fpie -fno-asynchronous-unwind-tables -Wno-address -fno-omit-frame-pointer -flto -DUSING_LTO -nostdinc -nostdlib -DUEFI_C_SOURCE -c -o /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/./AutoGen.obj -I/home/luying/uefi_workspace/edk2/lywhPkg/Applications/Uefi_Main -I/home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG -I/home/luying/uefi_workspace/edk2/MdePkg -I/home/luying/uefi_workspace/edk2/MdePkg/Include -I/home/luying/uefi_workspace/edk2/MdePkg/Test/UnitTest/Include -I/home/luying/uefi_workspace/edk2/MdePkg/Test/Mock/Include -I/home/luying/uefi_workspace/edk2/MdePkg/Library/MipiSysTLib/mipisyst/library/include -I/home/luying/uefi_workspace/edk2/MdePkg/Include/X64 -I/home/luying/uefi_workspace/edk2/MdeModulePkg -I/home/luying/uefi_workspace/edk2/MdeModulePkg/Include -I/home/luying/uefi_workspace/edk2/MdeModulePkg/Test/Mock/Include /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/AutoGen.c
#将Uefi_Main.c编译为Uefi_Main.obj
"gcc" -MMD -MF /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/Uefi_Main_ly.obj.deps -g -Os -fshort-wchar -fno-builtin -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -include AutoGen.h -fno-common -ffunction-sections -fdata-sections -DSTRING_ARRAY_NAME=Uefi_Main_lyStrings -m64 -fno-stack-protector "-DEFIAPI=__attribute__((ms_abi))" -maccumulate-outgoing-args -mno-red-zone -Wno-address -mcmodel=small -fpie -fno-asynchronous-unwind-tables -Wno-address -fno-omit-frame-pointer -flto -DUSING_LTO -nostdinc -nostdlib -DUEFI_C_SOURCE -c -o /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/./Uefi_Main_ly.obj -I/home/luying/uefi_workspace/edk2/lywhPkg/Applications/Uefi_Main -I/home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG -I/home/luying/uefi_workspace/edk2/MdePkg -I/home/luying/uefi_workspace/edk2/MdePkg/Include -I/home/luying/uefi_workspace/edk2/MdePkg/Test/UnitTest/Include -I/home/luying/uefi_workspace/edk2/MdePkg/Test/Mock/Include -I/home/luying/uefi_workspace/edk2/MdePkg/Library/MipiSysTLib/mipisyst/library/include -I/home/luying/uefi_workspace/edk2/MdePkg/Include/X64 -I/home/luying/uefi_workspace/edk2/MdeModulePkg -I/home/luying/uefi_workspace/edk2/MdeModulePkg/Include -I/home/luying/uefi_workspace/edk2/MdeModulePkg/Test/Mock/Include /home/luying/uefi_workspace/edk2/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly.c
#生成静态链接库
"gcc-ar" cr /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/Uefi_Main_ly.lib  @/home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/object_files.lst
#生成动态链接库
"gcc" -o /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/Uefi_Main_ly.dll -nostdlib -Wl,-n,-q,--gc-sections -z common-page-size=0x40 -Wl,--entry,_ModuleEntryPoint -u _ModuleEntryPoint -Wl,-Map,/home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/Uefi_Main_ly.map,--whole-archive -Wl,-melf_x86_64,--oformat=elf64-x86-64,-pie -flto -Os -Wl,--start-group,@/home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/static_library_files.lst,--end-group -g -Os -fshort-wchar -fno-builtin -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -include AutoGen.h -fno-common -ffunction-sections -fdata-sections -DSTRING_ARRAY_NAME=Uefi_Main_lyStrings -m64 -fno-stack-protector "-DEFIAPI=__attribute__((ms_abi))" -maccumulate-outgoing-args -mno-red-zone -Wno-address -mcmodel=small -fpie -fno-asynchronous-unwind-tables -Wno-address -fno-omit-frame-pointer -flto -DUSING_LTO -nostdinc -nostdlib -DUEFI_C_SOURCE -Wl,--defsym=PECOFF_HEADER_SIZE=0x228 -Wl,--script=/home/luying/uefi_workspace/edk2/BaseTools/Scripts/GccBase.lds -Wno-error
#利用GenFw生成efi文件
"GenFw" -e UEFI_APPLICATION -o /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/OUTPUT/Uefi_Main_ly.efi /home/luying/uefi_workspace/edk2/Build/lywhPkg/DEBUG_GCC5/X64/lywhPkg/Applications/Uefi_Main/Uefi_Main_ly/DEBUG/Uefi_Main_ly.dll

Build源码

        通常UEFI的编译包括以下三个步骤:

make -C BaseTools
. edksetup.sh
build -t CompilerName -A Arch -p PkgName

1、其中make -C BaseTools编译BaseTools下的工具包

2、而edksetup.sh是准备工作的核心,主要做的工作有设定工作目录,设定环境变量,设定工作目录和环境变量以及文件运行的入口,获取运行参数并按需执行。

3、build,开始编译

根据build打印在终端的信息去查找,发现来自于build.py文件,整个实现流程如下

针对其中build类的注释可以看到该类实现build的流程

        1、从工作区路径下的Conf文件内的target.txt与tools_def.txt加载配置项

        2、解析dsc文件

        3、解析FDF文件

        4、建立build数据库,解析其他文件例如module和package

        5、生成AutoGen文件、依赖文件、makefile文件

        6、唤起build命令

## The class implementing the EDK2 build process
#
#   The build process includes:
#       1. Load configuration from target.txt and tools_def.txt in $(WORKSPACE)/Conf
#       2. Parse DSC file of active platform
#       3. Parse FDF file if any
#       4. Establish build database, including parse all other files (module, package)
#       5. Create AutoGen files (C code file, depex file, makefile) if necessary
#       6. Call build command
#
class Build():
    def __init__(self, Target, WorkspaceDir, BuildOptions,log_q):
    def StartAutoGen(self,mqueue, DataPipe,SkipAutoGen,PcdMaList,cqueue):
    def GetToolChainAndFamilyFromDsc (self, File):
    def LoadConfiguration(self):
    def InitBuild(self):
    def InitPreBuild(self):
    def InitPostBuild(self):
    def PassCommandOption(self, BuildTarget, TargetArch, ToolChain, PlatformFile, Target):
    def LaunchPrebuild(self):
    def LaunchPostbuild(self):
    def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False, FfsCommand=None, PcdMaList=None):
    def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
    def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True, ModeIsSmm = False):
    def _CollectFvMapBuffer (self, MapBuffer, Wa, ModuleList):
    def _CollectModuleMapBuffer (self, MapBuffer, ModuleList):
    def _SaveMapFile (self, MapBuffer, Wa):
    def _BuildPlatform(self):
    def _BuildModule(self):
    def _GenFfsCmd(self,ArchList):
    def VerifyAutoGenFiles(self):
    def SetupMakeSetting(self,Wa):
    def PerformAutoGen(self,BuildTarget,ToolChain):
    def _MultiThreadBuildPlatform(self):
    def GetFreeSizeThreshold(self):
    def CheckFreeSizeThreshold(self, Threshold=None, FvDir=None):
    def CreateGuidedSectionToolsFile(self,Wa):
    def GetRealPathOfTool (self, tool):
    def Launch(self):
    def CreateAsBuiltInf(self):
    def GenDestCache(self):
    def GenLocalPreMakeCache(self):
    def Relinquish(self):

         Build源码下的构建平台整体执行流程如下,若构建模块,则_BuildPlatform改为_BuildModule且不需要调用_Buildpa.

Main()->MyBuild->Build->__init__->...                                  #让MyBuild=Build来实例化一个Build类,对Build类进行初始化,设定及检验用于build的环境,包括加载target.txt中的编译器,dsc文件中的描述等,用于生成最终的编译规则.
->MyBuild.Launch->_BuildPlatform->WorkspaceAutoGen->PlatformAutoGen    #调用Build类下的Launch函数启动,随后调用_BuildPlatform通过解析FDF文件和INF文件,生成相应的C代码(宏变量)和Makefile(编译规则)
->_BuildPa->_GenFfsCmd                                                 #在_BuildPlatform函数内调用编译_BuildPa模块
->_CollectModuleMapBuffer                                              #根据PCD修改EFI的内存分布,并获取modules的内存分布,用于重定位modules,链接生成最终的FD文件
->_Build                                                               #编译模块
->_CollectFvMapBuffer                                                  #获取重定位FV的信息

__init__     

        它用于初始化一个名为 `_Build` 的类的实例。以下是代码中的主要初始化步骤和属性设置:

1. 初始化工作目录和构建目标等基本属性:
   - `WorkspaceDir`:设置工作目录,通常是项目的根目录。
   - `Target`:设置构建目标。
   - `PlatformFile`:设置平台文件。
   - `ModuleFile`:设置模块文件。
   - `ArchList`:设置目标架构列表。
   - `ToolChainList`:设置工具链列表。
   - `BuildTargetList`:设置构建目标列表。
   - `Fdf`:设置 Flash 文件系统描述文件。
   - `FdList`:设置 ROM 映像列表。
   - `FvList`:设置 FV 映像列表。
   - `CapList`:设置能力名(Capability)列表。
   - `SilentMode`:设置是否启用静默模式。
   - `ThreadNumber`:设置线程数量。
   - `SkipAutoGen`:设置是否跳过自动生成。
   - `Reparse`:设置是否重新解析。
   - `SkuId`:设置 SKU ID。
   - `ConfDirectory`:设置配置目录。
   - `SpawnMode`:设置是否启用 Spawn 模式。
   - `BuildReport`:设置构建报告。
   - `AutoGenTime`:初始化自动生成时间。
   - `MakeTime`:初始化 Make 时间。
   - `GenFdsTime`:初始化生成 FDS 时间。
   - `MakeFileName`:初始化 Make 文件名。
   - `UniFlag`:设置构建标志。
   - `BuildModules`:初始化构建模块列表。
   - `HashSkipModules`:初始化哈希跳过模块列表。
   - `Db_Flag`:初始化 BuildDB 标志。
   - `LaunchPrebuildFlag`:初始化启动预构建标志。
   - `PlatformBuildPath`:设置平台构建路径。
   - `log_q`:初始化日志队列。

2. 设置全局构建选项和标志:
   - 根据构建选项,设置全局构建选项,如 `gIgnoreSource`、`gUseHashCache`、`gBinCacheDest`、`gBinCacheSource`、`gEnableGenfdsMultiThread`、`gDisableIncludePathCheck` 等。

3. 验证构建选项:
   - 检查是否启用二进制缓存,并根据情况检查是否使用哈希缓存,同时检查二进制源缓存与二进制目标缓存的组合是否合法。

4. 设置二进制缓存路径:
   - 根据全局构建选项设置二进制缓存的源路径(`gBinCacheSource`)和目标路径(`gBinCacheDest`)。

5. 初始化构建数据库(`BuildDB`)。

6. 初始化其他属性:
   - `Platform`:初始化平台对象为 `None`。
   - `ToolChainFamily`:初始化工具链家族为 `None`。
   - `LoadFixAddress`:初始化加载固定地址为 `0`。
   - `BuildModules`:初始化构建模块列表为空。
   - `HashSkipModules`:初始化哈希跳过模块列表为空。
   - `Db_Flag`:初始化构建数据库标志为 `False`。
   - `LaunchPrebuildFlag`:初始化启动预构建标志为 `False`。
   - `PlatformBuildPath`:设置平台构建路径。
   - `log_q`:设置日志队列。

7. 初始化构建进度器(`Progressor`)以便在构建过程中显示进度信息。

8. 打印构建环境和配置信息。

9. 初始化预构建(`Prebuild`)和后构建(`Postbuild`)。

10. 如果启用了预构建,执行预构建操作。

11. 初始化构建过程。

12. 初始化各种缓存和状态信息。

        最终,`__init__` 函数对类的各种属性进行了初始化,准备了构建过程所需的环境和配置信息。这些属性将在后续的构建过程中使用。

def __init__(self, Target, WorkspaceDir, BuildOptions,log_q):
        self.WorkspaceDir   = WorkspaceDir
        self.Target         = Target
        self.PlatformFile   = BuildOptions.PlatformFile
        self.ModuleFile     = BuildOptions.ModuleFile
        self.ArchList       = BuildOptions.TargetArch
        self.ToolChainList  = BuildOptions.ToolChain
        self.BuildTargetList= BuildOptions.BuildTarget
        self.Fdf            = BuildOptions.FdfFile
        self.FdList         = BuildOptions.RomImage
        self.FvList         = BuildOptions.FvImage
        self.CapList        = BuildOptions.CapName
        self.SilentMode     = BuildOptions.SilentMode
        self.ThreadNumber   = 1
        self.SkipAutoGen    = BuildOptions.SkipAutoGen
        self.Reparse        = BuildOptions.Reparse
        self.SkuId          = BuildOptions.SkuId
        if self.SkuId:
            GlobalData.gSKUID_CMD = self.SkuId
        self.ConfDirectory = BuildOptions.ConfDirectory
        self.SpawnMode      = True
        self.BuildReport    = BuildReport(BuildOptions.ReportFile, BuildOptions.ReportType)
        self.AutoGenTime    = 0
        self.MakeTime       = 0
        self.GenFdsTime     = 0
        self.MakeFileName   = ""
        TargetObj = TargetTxtDict()
        ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"),"Conf")))
        self.TargetTxt = TargetObj.Target
        self.ToolDef = ToolDefObj.ToolDef
        GlobalData.BuildOptionPcd     = BuildOptions.OptionPcd if BuildOptions.OptionPcd else []
        #Set global flag for build mode
        GlobalData.gIgnoreSource = BuildOptions.IgnoreSources
        GlobalData.gUseHashCache = BuildOptions.UseHashCache
        GlobalData.gBinCacheDest   = BuildOptions.BinCacheDest
        GlobalData.gBinCacheSource = BuildOptions.BinCacheSource
        GlobalData.gEnableGenfdsMultiThread = not BuildOptions.NoGenfdsMultiThread
        GlobalData.gDisableIncludePathCheck = BuildOptions.DisableIncludePathCheck

        if GlobalData.gBinCacheDest and not GlobalData.gUseHashCache:
            EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination must be used together with --hash.")

        if GlobalData.gBinCacheSource and not GlobalData.gUseHashCache:
            EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-source must be used together with --hash.")

        if GlobalData.gBinCacheDest and GlobalData.gBinCacheSource:
            EdkLogger.error("build", OPTION_NOT_SUPPORTED, ExtraData="--binary-destination can not be used together with --binary-source.")

        if GlobalData.gBinCacheSource:
            BinCacheSource = os.path.normpath(GlobalData.gBinCacheSource)
            if not os.path.isabs(BinCacheSource):
                BinCacheSource = mws.join(self.WorkspaceDir, BinCacheSource)
            GlobalData.gBinCacheSource = BinCacheSource
        else:
            if GlobalData.gBinCacheSource is not None:
                EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-source.")

        if GlobalData.gBinCacheDest:
            BinCacheDest = os.path.normpath(GlobalData.gBinCacheDest)
            if not os.path.isabs(BinCacheDest):
                BinCacheDest = mws.join(self.WorkspaceDir, BinCacheDest)
            GlobalData.gBinCacheDest = BinCacheDest
        else:
            if GlobalData.gBinCacheDest is not None:
                EdkLogger.error("build", OPTION_VALUE_INVALID, ExtraData="Invalid value of option --binary-destination.")

        GlobalData.gDatabasePath = os.path.normpath(os.path.join(GlobalData.gConfDirectory, GlobalData.gDatabasePath))
        if not os.path.exists(os.path.join(GlobalData.gConfDirectory, '.cache')):
            os.makedirs(os.path.join(GlobalData.gConfDirectory, '.cache'))
        self.Db = BuildDB
        self.BuildDatabase = self.Db.BuildObject
        self.Platform = None
        self.ToolChainFamily = None
        self.LoadFixAddress = 0
        self.UniFlag        = BuildOptions.Flag
        self.BuildModules = []
        self.HashSkipModules = []
        self.Db_Flag = False
        self.LaunchPrebuildFlag = False
        self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory, '.cache', '.PlatformBuild')
        if BuildOptions.CommandLength:
            GlobalData.gCommandMaxLength = BuildOptions.CommandLength

        # print dot character during doing some time-consuming work
        self.Progress = Utils.Progressor()
        # print current build environment and configuration
        EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"]))
        if "PACKAGES_PATH" in os.environ:
            # WORKSPACE env has been converted before. Print the same path style with WORKSPACE env.
            EdkLogger.quiet("%-16s = %s" % ("PACKAGES_PATH", os.path.normcase(os.path.normpath(os.environ["PACKAGES_PATH"]))))
        EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_PATH", os.environ["EDK_TOOLS_PATH"]))
        if "EDK_TOOLS_BIN" in os.environ:
            # Print the same path style with WORKSPACE env.
            EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"]))))
        EdkLogger.quiet("%-16s = %s" % ("CONF_PATH", GlobalData.gConfDirectory))
        if "PYTHON3_ENABLE" in os.environ:
            PYTHON3_ENABLE = os.environ["PYTHON3_ENABLE"]
            if PYTHON3_ENABLE != "TRUE":
                PYTHON3_ENABLE = "FALSE"
            EdkLogger.quiet("%-16s = %s" % ("PYTHON3_ENABLE", PYTHON3_ENABLE))
        if "PYTHON_COMMAND" in os.environ:
            EdkLogger.quiet("%-16s = %s" % ("PYTHON_COMMAND", os.environ["PYTHON_COMMAND"]))
        self.InitPreBuild()
        self.InitPostBuild()
        if self.Prebuild:
            EdkLogger.quiet("%-16s = %s" % ("PREBUILD", self.Prebuild))
        if self.Postbuild:
            EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.Postbuild))
        if self.Prebuild:
            self.LaunchPrebuild()
            TargetObj = TargetTxtDict()
            ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"), "Conf")))
            self.TargetTxt = TargetObj.Target
            self.ToolDef = ToolDefObj.ToolDef
        if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)):
            self.InitBuild()

        self.AutoGenMgr = None
        EdkLogger.info("")
        os.chdir(self.WorkspaceDir)
        self.log_q = log_q
        GlobalData.file_lock =  mp.Lock()
        # Init cache data for local only
        GlobalData.gPackageHashFile = dict()
        GlobalData.gModulePreMakeCacheStatus = dict()
        GlobalData.gModuleMakeCacheStatus = dict()
        GlobalData.gHashChainStatus = dict()
        GlobalData.gCMakeHashFile = dict()
        GlobalData.gModuleHashFile = dict()
        GlobalData.gFileHashDict = dict()
        GlobalData.gModuleAllCacheStatus = set()
        GlobalData.gModuleCacheHit = set()

 _BuildPlatform

        它用于构建平台(Platform)的过程。以下是该函数的主要功能和作用:

1. 清空平台构建文件:
   - 函数首先清空平台构建文件(`PlatformBuildPath`)内容,以防止手动编辑。

2. 遍历构建目标(`BuildTarget`)列表:
   - 函数会遍历构建目标列表,针对每个构建目标执行构建操作。这通常包括不同工具链(ToolChain)的构建。

3. 设置全局定义(GlobalDefines):
   - 函数会根据当前的构建目标、工具链等信息设置全局定义,以便在后续构建过程中使用。

4. 创建 WorkspaceAutoGen 对象:
   - 通过创建 `WorkspaceAutoGen` 对象,函数获取了构建平台的相关信息,包括构建目标、工具链、架构等。
   - 函数会生成构建平台所需的 Makefile。

5. 处理多线程 FFS 构建命令:
   - 如果启用了多线程 FFS 构建(`gEnableGenfdsMultiThread` 为真)且存在 Flash 文件系统描述文件(FDF),函数会生成 FFS 构建命令(CmdListDict)。

6. 遍历支持的架构:
   - 函数遍历平台支持的架构(`ArchList`)。
   - 对于每个架构,函数创建 `PlatformAutoGen` 对象(`Pa`)以获取平台信息。
   - 函数遍历平台上的模块(`Module`)并创建 `ModuleAutoGen` 对象(`Ma`)用于代码生成和 Makefile 生成。
   - 如果模块具有 PCD 驱动程序(`PcdIsDriver` 为真),则将其添加到 `PcdMaList` 中。

7. 执行 `_BuildPa` 函数:
   - 函数调用 `_BuildPa` 函数来执行构建平台的操作,包括生成代码、生成 Makefile 等。
   - 向 `_BuildPa` 函数传递了构建目标、`Pa` 对象和 FFS 构建命令(CmdListDict)。

8. 创建 MAP 文件:
   - 如果构建目标是 `""`、`"all"` 或 `"fds"`,函数会为每个架构创建 MAP 文件。
   - 在创建 MAP 文件之前,会检查是否需要重新定位模块的内存地址。
   - 如果存在 FDF 文件,函数会重新构建 Flash 文件系统(FDS)并创建 MAP 文件。

9. 创建 GUID 信息工具文件:
   - 函数调用 `CreateGuidedSectionToolsFile` 来创建 GUID 信息工具文件。

        总的来说,`_BuildPlatform` 函数是用于构建平台的核心函数,它处理了平台的多线程构建、代码生成、FFS 构建、MAP 文件生成等多个关键步骤。它在整个构建系统中起到了重要作用,确保了平台的正确构建和生成。

def _BuildPlatform(self):
        SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
        for BuildTarget in self.BuildTargetList:
            GlobalData.gGlobalDefines['TARGET'] = BuildTarget
            index = 0
            for ToolChain in self.ToolChainList:
                GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
                GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
                GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
                index += 1
                Wa = WorkspaceAutoGen(
                        self.WorkspaceDir,
                        self.PlatformFile,
                        BuildTarget,
                        ToolChain,
                        self.ArchList,
                        self.BuildDatabase,
                        self.TargetTxt,
                        self.ToolDef,
                        self.Fdf,
                        self.FdList,
                        self.FvList,
                        self.CapList,
                        self.SkuId,
                        self.UniFlag,
                        self.Progress
                        )
                self.Fdf = Wa.FdfFile
                self.LoadFixAddress = Wa.Platform.LoadFixAddress
                self.BuildReport.AddPlatformReport(Wa)
                self.Progress.Stop("done!")

                # Add ffs build to makefile
                CmdListDict = {}
                if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
                    CmdListDict = self._GenFfsCmd(Wa.ArchList)

                for Arch in Wa.ArchList:
                    PcdMaList    = []
                    GlobalData.gGlobalDefines['ARCH'] = Arch
                    Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
                    for Module in Pa.Platform.Modules:
                        # Get ModuleAutoGen object to generate C code file and makefile
                        Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)
                        if Ma is None:
                            continue
                        if Ma.PcdIsDriver:
                            Ma.PlatformInfo = Pa
                            Ma.Workspace = Wa
                            PcdMaList.append(Ma)
                        self.BuildModules.append(Ma)
                    Pa.DataPipe.DataContainer = {"FfsCommand":CmdListDict}
                    Pa.DataPipe.DataContainer = {"Workspace_timestamp": Wa._SrcTimeStamp}
                    self._BuildPa(self.Target, Pa, FfsCommand=CmdListDict,PcdMaList=PcdMaList)

                # Create MAP file when Load Fix Address is enabled.
                if self.Target in ["", "all", "fds"]:
                    for Arch in Wa.ArchList:
                        GlobalData.gGlobalDefines['ARCH'] = Arch
                        #
                        # Check whether the set fix address is above 4G for 32bit image.
                        #
                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
                            EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platform with IA32 or ARM arch modules")
                    #
                    # Get Module List
                    #
                    ModuleList = {}
                    for Pa in Wa.AutoGenObjectList:
                        for Ma in Pa.ModuleAutoGenList:
                            if Ma is None:
                                continue
                            if not Ma.IsLibrary:
                                ModuleList[Ma.Guid.upper()] = Ma

                    MapBuffer = []
                    if self.LoadFixAddress != 0:
                        #
                        # Rebase module to the preferred memory address before GenFds
                        #
                        self._CollectModuleMapBuffer(MapBuffer, ModuleList)
                    if self.Fdf:
                        #
                        # create FDS again for the updated EFI image
                        #
                        self._Build("fds", Wa)
                        #
                        # Create MAP file for all platform FVs after GenFds.
                        #
                        self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
                    #
                    # Save MAP buffer into MAP file.
                    #
                    self._SaveMapFile (MapBuffer, Wa)
                self.CreateGuidedSectionToolsFile(Wa)

_BuildModule      

        它用于构建模块(modules),其中包括多个步骤和逻辑。以下是该函数的主要功能和作用:

1. 遍历构建目标(`BuildTarget`)列表:
   - 函数首先遍历构建目标列表,针对每个构建目标执行构建操作。这通常包括不同架构(Arch)和工具链(ToolChain)的不同构建目标。

2. 设置全局定义(GlobalDefines):
   - 函数会根据当前的构建目标、工具链等信息设置全局定义,以便在后续构建过程中使用。

3. 创建 WorkspaceAutoGen 对象:
   - 通过创建 `WorkspaceAutoGen` 对象,函数获取了构建平台(Platform)的相关信息,包括构建目标、工具链、架构等。
   - 函数会生成构建平台所需的 Makefile。

4. 处理 FFS 构建命令:
   - 如果启用了多线程 FFS 构建(`gEnableGenfdsMultiThread` 为真)且存在 Flash 文件系统描述文件(FDF),函数会生成 FFS 构建命令(CmdListDict)。

5. 处理多线程构建和自动代码生成:
   - 函数使用多线程构建模块(Ma),每个模块都代表一个 EDK II 模块。
   - 对于每个模块,函数检查是否需要自动生成代码文件和 Makefile,然后执行构建操作。
   - 如果目标是 'genc' 或 'genmake',则仅生成代码文件或 Makefile 并立即返回。

6. 处理缓存操作:
   - 如果启用了缓存操作,函数会根据缓存类型执行相应的缓存生成或更新操作。

7. 构建报告生成:
   - 函数会生成构建报告,其中包括构建模块的详细信息。

8. 创建 MAP 文件:
   - 如果目标是 'fds'(生成 Flash 文件系统),函数会执行 Flash 文件系统生成操作。
   - 在这个过程中,会检查内存地址的设置,然后生成 Flash 文件系统(FDS)和 MAP 文件。

        总的来说,`_BuildModule` 函数是用于构建模块的核心函数,它处理了模块的多线程构建、代码生成、缓存操作、构建报告生成等多个关键步骤。它在整个构建系统中起到了重要作用,确保了模块的正确构建和生成。

def _BuildModule(self):
        for BuildTarget in self.BuildTargetList:
            GlobalData.gGlobalDefines['TARGET'] = BuildTarget
            index = 0
            for ToolChain in self.ToolChainList:
                WorkspaceAutoGenTime = time.time()
                GlobalData.gGlobalDefines['TOOLCHAIN'] = ToolChain
                GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = ToolChain
                GlobalData.gGlobalDefines['FAMILY'] = self.ToolChainFamily[index]
                index += 1
                #
                # module build needs platform build information, so get platform
                # AutoGen first
                #
                Wa = WorkspaceAutoGen(
                        self.WorkspaceDir,
                        self.PlatformFile,
                        BuildTarget,
                        ToolChain,
                        self.ArchList,
                        self.BuildDatabase,
                        self.TargetTxt,
                        self.ToolDef,
                        self.Fdf,
                        self.FdList,
                        self.FvList,
                        self.CapList,
                        self.SkuId,
                        self.UniFlag,
                        self.Progress,
                        self.ModuleFile
                        )
                self.Fdf = Wa.FdfFile
                self.LoadFixAddress = Wa.Platform.LoadFixAddress
                Wa.CreateMakeFile(False)
                # Add ffs build to makefile
                CmdListDict = None
                if GlobalData.gEnableGenfdsMultiThread and self.Fdf:
                    CmdListDict = self._GenFfsCmd(Wa.ArchList)

                GlobalData.file_lock = mp.Lock()
                GlobalData.FfsCmd = CmdListDict

                self.Progress.Stop("done!")
                MaList = []
                ExitFlag = threading.Event()
                ExitFlag.clear()
                self.AutoGenTime += int(round((time.time() - WorkspaceAutoGenTime)))
                for Arch in Wa.ArchList:
                    AutoGenStart = time.time()
                    GlobalData.gGlobalDefines['ARCH'] = Arch
                    Pa = PlatformAutoGen(Wa, self.PlatformFile, BuildTarget, ToolChain, Arch)
                    for Module in Pa.Platform.Modules:
                        if self.ModuleFile.Dir == Module.Dir and self.ModuleFile.Name == Module.Name:
                            Ma = ModuleAutoGen(Wa, Module, BuildTarget, ToolChain, Arch, self.PlatformFile,Pa.DataPipe)
                            if Ma is None:
                                continue
                            if Ma.PcdIsDriver:
                                Ma.PlatformInfo = Pa
                                Ma.Workspace = Wa
                            MaList.append(Ma)

                            if GlobalData.gUseHashCache and not GlobalData.gBinCacheDest and self.Target in [None, "", "all"]:
                                if Ma.CanSkipbyPreMakeCache():
                                    continue
                                else:
                                    self.PreMakeCacheMiss.add(Ma)

                            # Not to auto-gen for targets 'clean', 'cleanlib', 'cleanall', 'run', 'fds'
                            if self.Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
                                # for target which must generate AutoGen code and makefile
                                if not self.SkipAutoGen or self.Target == 'genc':
                                    self.Progress.Start("Generating code")
                                    Ma.CreateCodeFile(True)
                                    self.Progress.Stop("done!")
                                if self.Target == "genc":
                                    return True
                                if not self.SkipAutoGen or self.Target == 'genmake':
                                    self.Progress.Start("Generating makefile")
                                    if CmdListDict and self.Fdf and (Module.Path, Arch) in CmdListDict:
                                        Ma.CreateMakeFile(True, CmdListDict[Module.Path, Arch])
                                        del CmdListDict[Module.Path, Arch]
                                    else:
                                        Ma.CreateMakeFile(True)
                                    self.Progress.Stop("done!")
                                if self.Target == "genmake":
                                    return True

                                if GlobalData.gBinCacheSource and self.Target in [None, "", "all"]:
                                    if Ma.CanSkipbyMakeCache():
                                        continue
                                    else:
                                        self.MakeCacheMiss.add(Ma)

                            self.BuildModules.append(Ma)
                    self.AutoGenTime += int(round((time.time() - AutoGenStart)))
                    MakeStart = time.time()
                    for Ma in self.BuildModules:
                        if not Ma.IsBinaryModule:
                            Bt = BuildTask.New(ModuleMakeUnit(Ma, Pa.BuildCommand,self.Target))
                        # Break build if any build thread has error
                        if BuildTask.HasError():
                            # we need a full version of makefile for platform
                            ExitFlag.set()
                            BuildTask.WaitForComplete()
                            Pa.CreateMakeFile(False)
                            EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
                        # Start task scheduler
                        if not BuildTask.IsOnGoing():
                            BuildTask.StartScheduler(self.ThreadNumber, ExitFlag)

                    # in case there's an interruption. we need a full version of makefile for platform
                    Pa.CreateMakeFile(False)
                    if BuildTask.HasError():
                        EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)
                    self.MakeTime += int(round((time.time() - MakeStart)))

                MakeContiue = time.time()
                ExitFlag.set()
                BuildTask.WaitForComplete()
                self.CreateAsBuiltInf()
                if GlobalData.gBinCacheDest:
                    self.GenDestCache()
                elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:
                    # Only for --hash
                    # Update PreMakeCacheChain files
                    self.GenLocalPreMakeCache()
                self.BuildModules = []
                self.MakeTime += int(round((time.time() - MakeContiue)))
                if BuildTask.HasError():
                    EdkLogger.error("build", BUILD_ERROR, "Failed to build module", ExtraData=GlobalData.gBuildingModule)

                self.BuildReport.AddPlatformReport(Wa, MaList)
                if MaList == []:
                    EdkLogger.error(
                                'build',
                                BUILD_ERROR,
                                "Module for [%s] is not a component of active platform."\
                                " Please make sure that the ARCH and inf file path are"\
                                " given in the same as in [%s]" % \
                                    (', '.join(Wa.ArchList), self.PlatformFile),
                                ExtraData=self.ModuleFile
                                )
                # Create MAP file when Load Fix Address is enabled.
                if self.Target == "fds" and self.Fdf:
                    for Arch in Wa.ArchList:
                        #
                        # Check whether the set fix address is above 4G for 32bit image.
                        #
                        if (Arch == 'IA32' or Arch == 'ARM') and self.LoadFixAddress != 0xFFFFFFFFFFFFFFFF and self.LoadFixAddress >= 0x100000000:
                            EdkLogger.error("build", PARAMETER_INVALID, "FIX_LOAD_TOP_MEMORY_ADDRESS can't be set to larger than or equal to 4G for the platorm with IA32 or ARM arch modules")
                    #
                    # Get Module List
                    #
                    ModuleList = {}
                    for Pa in Wa.AutoGenObjectList:
                        for Ma in Pa.ModuleAutoGenList:
                            if Ma is None:
                                continue
                            if not Ma.IsLibrary:
                                ModuleList[Ma.Guid.upper()] = Ma

                    MapBuffer = []
                    if self.LoadFixAddress != 0:
                        #
                        # Rebase module to the preferred memory address before GenFds
                        #
                        self._CollectModuleMapBuffer(MapBuffer, ModuleList)
                    #
                    # create FDS again for the updated EFI image
                    #
                    GenFdsStart = time.time()
                    self._Build("fds", Wa)
                    self.GenFdsTime += int(round((time.time() - GenFdsStart)))
                    #
                    # Create MAP file for all platform FVs after GenFds.
                    #
                    self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
                    #
                    # Save MAP buffer into MAP file.
                    #
                    self._SaveMapFile (MapBuffer, Wa)

_BuildPa     

        这个 `_BuildPa` 函数是 edk2 的构建系统中的一个重要函数,它负责根据指定的目标(Target)执行不同的构建操作。以下是这个函数的主要功能和作用:

1. 构建模块、库和平台:
   - `_BuildPa` 函数可以用于构建不同级别的组件,包括模块、库和平台。
   - 根据传入的 `Target` 参数,可以选择构建模块、库、平台或执行清理操作(clean)。

2. 多线程构建:
   - 函数内部使用了多线程来并行构建不同的模块或库,以提高构建效率。
   - 对于模块、库的构建,它会将构建任务放入队列,并使用多线程执行。

3. 构建命令的生成和执行:
   - 函数会根据配置文件中的设置生成构建命令(BuildCommand)。
   - 对于模块、库的构建,它会执行相应的构建命令。
   - 对于平台级别的构建,它会生成 Makefile 和代码文件。

4. 清理操作:
   - 函数支持清理操作,包括清理模块、库、平台以及全部清理(cleanall)。

5. 其他功能:
   - 函数还包括了一些额外的功能,如生成缓存、更新数据管道、创建AsBuiltInf等。

        总的来说,`_BuildPa` 函数是构建系统的核心部分之一,用于管理和执行不同构建操作,以确保正确构建模块、库和平台。根据传入的目标,它可以执行不同级别的构建或清理操作,并支持多线程构建以提高效率。此外,它还负责生成构建命令和相应的文件。这个函数的设计是为了让构建系统更加灵活和可扩展。

def _BuildPa(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False, FfsCommand=None, PcdMaList=None):
        if AutoGenObject is None:
            return False
        if FfsCommand is None:
            FfsCommand = {}
        # skip file generation for cleanxxx targets, run and fds target
        if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
            # for target which must generate AutoGen code and makefile
            mqueue = mp.Queue()
            for m in AutoGenObject.GetAllModuleInfo:
                mqueue.put(m)
            mqueue.put((None,None,None,None,None,None,None))
            AutoGenObject.DataPipe.DataContainer = {"CommandTarget": self.Target}
            AutoGenObject.DataPipe.DataContainer = {"Workspace_timestamp": AutoGenObject.Workspace._SrcTimeStamp}
            AutoGenObject.CreateLibModuelDirs()
            AutoGenObject.DataPipe.DataContainer = {"LibraryBuildDirectoryList":AutoGenObject.LibraryBuildDirectoryList}
            AutoGenObject.DataPipe.DataContainer = {"ModuleBuildDirectoryList":AutoGenObject.ModuleBuildDirectoryList}
            AutoGenObject.DataPipe.DataContainer = {"FdsCommandDict": AutoGenObject.Workspace.GenFdsCommandDict}
            self.Progress.Start("Generating makefile and code")
            data_pipe_file = os.path.join(AutoGenObject.BuildDir, "GlobalVar_%s_%s.bin" % (str(AutoGenObject.Guid),AutoGenObject.Arch))
            AutoGenObject.DataPipe.dump(data_pipe_file)
            cqueue = mp.Queue()
            autogen_rt,errorcode = self.StartAutoGen(mqueue, AutoGenObject.DataPipe, self.SkipAutoGen, PcdMaList, cqueue)
            AutoGenIdFile = os.path.join(GlobalData.gConfDirectory,".AutoGenIdFile.txt")
            with open(AutoGenIdFile,"w") as fw:
                fw.write("Arch=%s\n" % "|".join((AutoGenObject.Workspace.ArchList)))
                fw.write("BuildDir=%s\n" % AutoGenObject.Workspace.BuildDir)
                fw.write("PlatformGuid=%s\n" % str(AutoGenObject.Guid))
            self.Progress.Stop("done!")
            if not autogen_rt:
                self.AutoGenMgr.TerminateWorkers()
                self.AutoGenMgr.join(1)
                raise FatalError(errorcode)
            AutoGenObject.CreateCodeFile(False)
            AutoGenObject.CreateMakeFile(False)
        else:
            # always recreate top/platform makefile when clean, just in case of inconsistency
            AutoGenObject.CreateCodeFile(True)
            AutoGenObject.CreateMakeFile(True)

        if EdkLogger.GetLevel() == EdkLogger.QUIET:
            EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))

        BuildCommand = AutoGenObject.BuildCommand
        if BuildCommand is None or len(BuildCommand) == 0:
            EdkLogger.error("build", OPTION_MISSING,
                            "No build command found for this module. "
                            "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
                                (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
                            ExtraData=str(AutoGenObject))

        # run
        if Target == 'run':
            return True

        # Fetch the MakeFileName.
        self.MakeFileName = AutoGenObject.MakeFileName

        # build modules
        if BuildModule:
            BuildCommand = BuildCommand + [Target]
            LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
            if GlobalData.gBinCacheDest:
                self.GenDestCache()
            elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:
                # Only for --hash
                # Update PreMakeCacheChain files
                self.GenLocalPreMakeCache()
            self.BuildModules = []
            return True

        # build library
        if Target == 'libraries':
            DirList = []
            for Lib in AutoGenObject.LibraryAutoGenList:
                if not Lib.IsBinaryModule:
                    DirList.append((os.path.join(AutoGenObject.BuildDir, Lib.BuildDir),Lib))
            for Lib, LibAutoGen in DirList:
                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, self.MakeFileName)), 'pbuild']
                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,LibAutoGen)
            return True

        # build module
        if Target == 'modules':
            DirList = []
            for Lib in AutoGenObject.LibraryAutoGenList:
                if not Lib.IsBinaryModule:
                    DirList.append((os.path.join(AutoGenObject.BuildDir, Lib.BuildDir),Lib))
            for Lib, LibAutoGen in DirList:
                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, self.MakeFileName)), 'pbuild']
                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,LibAutoGen)

            DirList = []
            for ModuleAutoGen in AutoGenObject.ModuleAutoGenList:
                if not ModuleAutoGen.IsBinaryModule:
                    DirList.append((os.path.join(AutoGenObject.BuildDir, ModuleAutoGen.BuildDir),ModuleAutoGen))
            for Mod,ModAutoGen in DirList:
                NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, self.MakeFileName)), 'pbuild']
                LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,ModAutoGen)
            self.CreateAsBuiltInf()
            if GlobalData.gBinCacheDest:
                self.GenDestCache()
            elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:
                # Only for --hash
                # Update PreMakeCacheChain files
                self.GenLocalPreMakeCache()
            self.BuildModules = []
            return True

        # cleanlib
        if Target == 'cleanlib':
            for Lib in AutoGenObject.LibraryBuildDirectoryList:
                LibMakefile = os.path.normpath(os.path.join(Lib, self.MakeFileName))
                if os.path.exists(LibMakefile):
                    NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
                    LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
            return True

        # clean
        if Target == 'clean':
            for Mod in AutoGenObject.ModuleBuildDirectoryList:
                ModMakefile = os.path.normpath(os.path.join(Mod, self.MakeFileName))
                if os.path.exists(ModMakefile):
                    NewBuildCommand = BuildCommand + ['-f', ModMakefile, 'cleanall']
                    LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
            for Lib in AutoGenObject.LibraryBuildDirectoryList:
                LibMakefile = os.path.normpath(os.path.join(Lib, self.MakeFileName))
                if os.path.exists(LibMakefile):
                    NewBuildCommand = BuildCommand + ['-f', LibMakefile, 'cleanall']
                    LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir)
            return True

        # cleanall
        if Target == 'cleanall':
            try:
                #os.rmdir(AutoGenObject.BuildDir)
                RemoveDirectory(AutoGenObject.BuildDir, True)
            except WindowsError as X:
                EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
        return True

 _Build

        这个 `_Build` 函数是 edk2 构建系统中的另一个核心函数,它用于执行不同类型的构建操作,类似于 `_BuildPa` 函数,但有一些不同之处。以下是这个函数的主要功能和作用:

1. 构建代码文件和 Makefile:
   - 根据传入的 `Target` 参数,函数可以选择生成代码文件、Makefile 或执行清理操作。
   - 对于需要生成代码文件和 Makefile 的目标(不包括清理目标),它会调用 `AutoGenObject` 的相应方法生成这些文件。

2. 清理操作:
   - 函数支持清理操作,包括清理模块、库、平台和全部清理(cleanall)。

3. 构建命令的生成和执行:
   - 函数会根据配置文件中的设置生成构建命令(BuildCommand)。
   - 对于模块的构建,它会执行相应的构建命令。

4. genfds 操作:
   - 如果 `Target` 是 'fds',函数会执行 `GenFdsApi` 来生成 Flash 文件系统(FDS)。

5. 运行操作:
   - 如果 `Target` 是 'run',函数将直接返回 True,表示运行操作已完成。

6. 创建 AsBuiltInf 文件:
   - 函数会调用 `CreateAsBuiltInf` 方法创建 AsBuiltInf 文件。

7. 缓存操作:
   - 函数支持缓存操作,包括生成缓存、更新数据管道、生成本地缓存等。

        总的来说,`_Build` 函数是构建系统的核心之一,用于执行不同类型的构建和清理操作,包括生成代码文件、Makefile、Flash 文件系统(FDS)等。它根据传入的 `Target` 参数决定执行哪种操作,并根据配置文件生成相应的构建命令。这个函数的设计是为了使构建系统更加灵活,并且支持各种不同的构建和清理操作。

def _Build(self, Target, AutoGenObject, CreateDepsCodeFile=True, CreateDepsMakeFile=True, BuildModule=False):
        if AutoGenObject is None:
            return False

        # skip file generation for cleanxxx targets, run and fds target
        if Target not in ['clean', 'cleanlib', 'cleanall', 'run', 'fds']:
            # for target which must generate AutoGen code and makefile
            if not self.SkipAutoGen or Target == 'genc':
                self.Progress.Start("Generating code")
                AutoGenObject.CreateCodeFile(CreateDepsCodeFile)
                self.Progress.Stop("done!")
            if Target == "genc":
                return True

            if not self.SkipAutoGen or Target == 'genmake':
                self.Progress.Start("Generating makefile")
                AutoGenObject.CreateMakeFile(CreateDepsMakeFile)
                #AutoGenObject.CreateAsBuiltInf()
                self.Progress.Stop("done!")
            if Target == "genmake":
                return True
        else:
            # always recreate top/platform makefile when clean, just in case of inconsistency
            AutoGenObject.CreateCodeFile(True)
            AutoGenObject.CreateMakeFile(True)

        if EdkLogger.GetLevel() == EdkLogger.QUIET:
            EdkLogger.quiet("Building ... %s" % repr(AutoGenObject))

        BuildCommand = AutoGenObject.BuildCommand
        if BuildCommand is None or len(BuildCommand) == 0:
            EdkLogger.error("build", OPTION_MISSING,
                            "No build command found for this module. "
                            "Please check your setting of %s_%s_%s_MAKE_PATH in Conf/tools_def.txt file." %
                                (AutoGenObject.BuildTarget, AutoGenObject.ToolChain, AutoGenObject.Arch),
                            ExtraData=str(AutoGenObject))

        # build modules
        if BuildModule:
            if Target != 'fds':
                BuildCommand = BuildCommand + [Target]
            AutoGenObject.BuildTime = LaunchCommand(BuildCommand, AutoGenObject.MakeFileDir)
            self.CreateAsBuiltInf()
            if GlobalData.gBinCacheDest:
                self.GenDestCache()
            elif GlobalData.gUseHashCache and not GlobalData.gBinCacheSource:
                # Only for --hash
                # Update PreMakeCacheChain files
                self.GenLocalPreMakeCache()
            self.BuildModules = []
            return True

        # genfds
        if Target == 'fds':
            if GenFdsApi(AutoGenObject.GenFdsCommandDict, self.Db):
                EdkLogger.error("build", COMMAND_FAILURE)
            Threshold = self.GetFreeSizeThreshold()
            if Threshold:
                self.CheckFreeSizeThreshold(Threshold, AutoGenObject.FvDir)
            return True

        # run
        if Target == 'run':
            return True

        # build library
        if Target == 'libraries':
            pass

        # not build modules


        # cleanall
        if Target == 'cleanall':
            try:
                #os.rmdir(AutoGenObject.BuildDir)
                RemoveDirectory(AutoGenObject.BuildDir, True)
            except WindowsError as X:
                EdkLogger.error("build", FILE_DELETE_FAILURE, ExtraData=str(X))
        return True

        在edk2的`build.py`文件中,`_BuildPa` 和 `_Build` 这两个函数具有不同的作用和功能,它们分别用于不同的构建任务。

1. `_BuildPa` 函数:
   - `_BuildPa` 函数用于构建 Platform AutoGen(`PlatformAutoGen`)对象,这个对象代表了平台(Platform)的自动化构建。
   - 平台是edk2项目的核心组件之一,它包括了一组模块(Module)、库文件(Library)以及其他相关配置。平台的构建过程包括生成代码、生成Makefile、构建Firmware File System(FFS)等任务。
   - `_BuildPa` 函数主要负责执行与平台构建相关的任务,包括生成平台的代码、Makefile,以及执行平台的构建。这些任务通常在构建整个平台时执行。

2. `_Build` 函数:
   - `_Build` 函数是用于执行构建任务的核心函数,它根据不同的构建目标(Build Target)执行不同的构建操作。
   - 在 `_Build` 函数中,会判断构建目标的类型,如果是 "fds" 则执行构建FDS(Firmware Device Image)的任务,如果是其他目标则执行模块(Module)的构建任务。
   - 对于模块的构建, `_Build` 函数会进一步调用 `_BuildModule` 函数,完成模块级别的构建。
   - `_Build` 函数还会在适当的时候执行生成 MAP 文件等辅助任务。

        总的来说,`_BuildPa` 和 `_Build` 函数分别负责不同层次的构建任务。`_BuildPa` 处理平台级别的构建,而 `_Build` 处理构建目标和模块级别的构建任务。这种结构有助于将构建过程分解为更小的任务单元,提高了代码的模块化和可维护性。