UEFI中的edk2编译流程_edk2代码走读

UEFI中的edk2编译流程_edk2代码走读FDF 文件用于描述固件在 flash 中的布局和位置 这些固件是与 UEFI 兼容的二进制镜像 一般来说 生成固件的源码中只有一个 FDF 文件 其作用是规定把哪些包编入 flash 中 并确定编入的位置 FD

大家好,欢迎来到IT知识分享网。

UEFI中的edk2编译流程_edk2代码走读

UEFI中的edk2编译流程_edk2代码走读

Build

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

UEFI中的edk2编译流程_edk2代码走读

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

UEFI中的edk2编译流程_edk2代码走读

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

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

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

UEFI中的edk2编译流程_edk2代码走读

UEFI中的edk2编译流程_edk2代码走读

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中的edk2编译流程_edk2代码走读

根据上表可以看到,从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中的edk2编译流程_edk2代码走读

生成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中的edk2编译流程_edk2代码走读

UEFI中的edk2编译流程_edk2代码走读

在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中的edk2编译流程_edk2代码走读

FFS Header

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

UEFI中的edk2编译流程_edk2代码走读

Section Header

Section的头包含了Section的Type与Length

UEFI中的edk2编译流程_edk2代码走读

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中的edk2编译流程_edk2代码走读

UEFI中的edk2编译流程_edk2代码走读

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 = 0x|gEmulatorPkgTokenSpaceGuid.PcdEmuFdBaseAddress:这里指定了 FD 的基地址。基地址是 FD 在内存中的起始物理地址。在这个示例中,基地址被设置为 0x,并且还引用了一个 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 (0x). If this address does not match the FV will get # relocated in place (works, but not a great idea). # BaseAddress = 0x|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|0x00 gEmulatorPkgTokenSpaceGuid.PcdEmuFlashFvRecoveryBase|gEmulatorPkgTokenSpaceGuid.PcdEmuFlashFvRecoverySize FV = FvRecovery 0x00|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 } 0x00|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. 设置全局构建选项和标志:
       – 根据构建选项,设置全局构建选项,如 gIgnoreSourcegUseHashCachegBinCacheDestgBinCacheSourcegEnableGenfdsMultiThreadgDisableIncludePathCheck 等。
  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 >= 0x: 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) 最后的话 最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家! 资料预览 给大家整理的视频资料: ![](https://img-blog.csdnimg.cn/img_convert/fe13ec7997bf00a3f5d87db0a3a30ac1.png) 给大家整理的电子书资料: ![](https://img-blog.csdnimg.cn/img_convert/61cd30ce91bf2da64b352adeaf.png) 如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力! 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) 最后的话 最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家! 资料预览 给大家整理的视频资料: [外链图片转存中...(img-gmPoTxxY-56)] 给大家整理的电子书资料: [外链图片转存中...(img-ViVjTf8Y-57)] 如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力! 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/112552.html

(0)
上一篇 2026-01-17 16:45
下一篇 2026-01-17 17:10

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信