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

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以点击这里获取!

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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` 这两个函数具有不同的作用和功能,它们分别用于不同的构建任务。


### 最后的话

最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!

### 资料预览

给大家整理的视频资料:

![](https://img-blog.csdnimg.cn/img_convert/0187fd5a2442e4197be320ad90c3d6a2.png)

给大家整理的电子书资料:

  

![](https://img-blog.csdnimg.cn/img_convert/6f5c6f5b3afd064f94f736b67b2251f1.png)



**如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!**

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618635766)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

d:
                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 这两个函数具有不同的作用和功能,它们分别用于不同的构建任务。

最后的话

最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!

资料预览

给大家整理的视频资料:

[外链图片转存中…(img-1chhl1DU-1715888654615)]

给大家整理的电子书资料:

[外链图片转存中…(img-3NkEckoD-1715888654616)]

如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以点击这里获取!

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 26
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值