diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/AutoGen/WorkspaceAutoGen.py | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/AutoGen/WorkspaceAutoGen.py')
-rwxr-xr-x | src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/AutoGen/WorkspaceAutoGen.py | 971 |
1 files changed, 971 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/AutoGen/WorkspaceAutoGen.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/AutoGen/WorkspaceAutoGen.py new file mode 100755 index 00000000..93624d0f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/AutoGen/WorkspaceAutoGen.py @@ -0,0 +1,971 @@ +## @file +# Create makefile for MS nmake and GNU make +# +# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## Import Modules +# +from __future__ import print_function +from __future__ import absolute_import +import os.path as path +import hashlib +from collections import defaultdict +from GenFds.FdfParser import FdfParser +from Workspace.WorkspaceCommon import GetModuleLibInstances +from AutoGen import GenMake +from AutoGen.AutoGen import AutoGen +from AutoGen.PlatformAutoGen import PlatformAutoGen +from AutoGen.BuildEngine import gDefaultBuildRuleFile +from Common.ToolDefClassObject import gDefaultToolsDefFile +from Common.StringUtils import NormPath +from Common.BuildToolError import * +from Common.DataType import * +from Common.Misc import * +import json + +## Regular expression for splitting Dependency Expression string into tokens +gDepexTokenPattern = re.compile("(\(|\)|\w+| \S+\.inf)") + +## Regular expression for match: PCD(xxxx.yyy) +gPCDAsGuidPattern = re.compile(r"^PCD\(.+\..+\)$") + +## Workspace AutoGen class +# +# This class is used mainly to control the whole platform build for different +# architecture. This class will generate top level makefile. +# +class WorkspaceAutoGen(AutoGen): + # call super().__init__ then call the worker function with different parameter count + def __init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs): + if not hasattr(self, "_Init"): + self._InitWorker(Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs) + self._Init = True + + ## Initialize WorkspaceAutoGen + # + # @param WorkspaceDir Root directory of workspace + # @param ActivePlatform Meta-file of active platform + # @param Target Build target + # @param Toolchain Tool chain name + # @param ArchList List of architecture of current build + # @param MetaFileDb Database containing meta-files + # @param BuildConfig Configuration of build + # @param ToolDefinition Tool chain definitions + # @param FlashDefinitionFile File of flash definition + # @param Fds FD list to be generated + # @param Fvs FV list to be generated + # @param Caps Capsule list to be generated + # @param SkuId SKU id from command line + # + def _InitWorker(self, WorkspaceDir, ActivePlatform, Target, Toolchain, ArchList, MetaFileDb, + BuildConfig, ToolDefinition, FlashDefinitionFile='', Fds=None, Fvs=None, Caps=None, SkuId='', UniFlag=None, + Progress=None, BuildModule=None): + self.BuildDatabase = MetaFileDb + self.MetaFile = ActivePlatform + self.WorkspaceDir = WorkspaceDir + self.Platform = self.BuildDatabase[self.MetaFile, TAB_ARCH_COMMON, Target, Toolchain] + GlobalData.gActivePlatform = self.Platform + self.BuildTarget = Target + self.ToolChain = Toolchain + self.ArchList = ArchList + self.SkuId = SkuId + self.UniFlag = UniFlag + + self.TargetTxt = BuildConfig + self.ToolDef = ToolDefinition + self.FdfFile = FlashDefinitionFile + self.FdTargetList = Fds if Fds else [] + self.FvTargetList = Fvs if Fvs else [] + self.CapTargetList = Caps if Caps else [] + self.AutoGenObjectList = [] + self._GuidDict = {} + + # there's many relative directory operations, so ... + os.chdir(self.WorkspaceDir) + + self.MergeArch() + self.ValidateBuildTarget() + + EdkLogger.info("") + if self.ArchList: + EdkLogger.info('%-16s = %s' % ("Architecture(s)", ' '.join(self.ArchList))) + EdkLogger.info('%-16s = %s' % ("Build target", self.BuildTarget)) + EdkLogger.info('%-16s = %s' % ("Toolchain", self.ToolChain)) + + EdkLogger.info('\n%-24s = %s' % ("Active Platform", self.Platform)) + if BuildModule: + EdkLogger.info('%-24s = %s' % ("Active Module", BuildModule)) + + if self.FdfFile: + EdkLogger.info('%-24s = %s' % ("Flash Image Definition", self.FdfFile)) + + EdkLogger.verbose("\nFLASH_DEFINITION = %s" % self.FdfFile) + + if Progress: + Progress.Start("\nProcessing meta-data") + # + # Mark now build in AutoGen Phase + # + # + # Collect Platform Guids to support Guid name in Fdfparser. + # + self.CollectPlatformGuids() + GlobalData.gAutoGenPhase = True + self.ProcessModuleFromPdf() + self.ProcessPcdType() + self.ProcessMixedPcd() + self.VerifyPcdsFromFDF() + self.CollectAllPcds() + for Pa in self.AutoGenObjectList: + Pa.FillData_LibConstPcd() + self.GeneratePkgLevelHash() + # + # Check PCDs token value conflict in each DEC file. + # + self._CheckAllPcdsTokenValueConflict() + # + # Check PCD type and definition between DSC and DEC + # + self._CheckPcdDefineAndType() + + self.CreateBuildOptionsFile() + self.CreatePcdTokenNumberFile() + self.GeneratePlatformLevelHash() + + # + # Merge Arch + # + def MergeArch(self): + if not self.ArchList: + ArchList = set(self.Platform.SupArchList) + else: + ArchList = set(self.ArchList) & set(self.Platform.SupArchList) + if not ArchList: + EdkLogger.error("build", PARAMETER_INVALID, + ExtraData = "Invalid ARCH specified. [Valid ARCH: %s]" % (" ".join(self.Platform.SupArchList))) + elif self.ArchList and len(ArchList) != len(self.ArchList): + SkippedArchList = set(self.ArchList).symmetric_difference(set(self.Platform.SupArchList)) + EdkLogger.verbose("\nArch [%s] is ignored because the platform supports [%s] only!" + % (" ".join(SkippedArchList), " ".join(self.Platform.SupArchList))) + self.ArchList = tuple(ArchList) + + # Validate build target + def ValidateBuildTarget(self): + if self.BuildTarget not in self.Platform.BuildTargets: + EdkLogger.error("build", PARAMETER_INVALID, + ExtraData="Build target [%s] is not supported by the platform. [Valid target: %s]" + % (self.BuildTarget, " ".join(self.Platform.BuildTargets))) + + def CollectPlatformGuids(self): + oriInfList = [] + oriPkgSet = set() + PlatformPkg = set() + for Arch in self.ArchList: + Platform = self.BuildDatabase[self.MetaFile, Arch, self.BuildTarget, self.ToolChain] + oriInfList = Platform.Modules + for ModuleFile in oriInfList: + ModuleData = self.BuildDatabase[ModuleFile, Platform._Arch, Platform._Target, Platform._Toolchain] + oriPkgSet.update(ModuleData.Packages) + for Pkg in oriPkgSet: + Guids = Pkg.Guids + GlobalData.gGuidDict.update(Guids) + if Platform.Packages: + PlatformPkg.update(Platform.Packages) + for Pkg in PlatformPkg: + Guids = Pkg.Guids + GlobalData.gGuidDict.update(Guids) + + @cached_property + def FdfProfile(self): + if not self.FdfFile: + self.FdfFile = self.Platform.FlashDefinition + + FdfProfile = None + if self.FdfFile: + Fdf = FdfParser(self.FdfFile.Path) + Fdf.ParseFile() + GlobalData.gFdfParser = Fdf + if Fdf.CurrentFdName and Fdf.CurrentFdName in Fdf.Profile.FdDict: + FdDict = Fdf.Profile.FdDict[Fdf.CurrentFdName] + for FdRegion in FdDict.RegionList: + if str(FdRegion.RegionType) == 'FILE' and self.Platform.VpdToolGuid in str(FdRegion.RegionDataList): + if int(FdRegion.Offset) % 8 != 0: + EdkLogger.error("build", FORMAT_INVALID, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion.Offset)) + FdfProfile = Fdf.Profile + else: + if self.FdTargetList: + EdkLogger.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self.FdTargetList)) + self.FdTargetList = [] + if self.FvTargetList: + EdkLogger.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self.FvTargetList)) + self.FvTargetList = [] + if self.CapTargetList: + EdkLogger.info("No flash definition file found. Capsule [%s] will be ignored." % " ".join(self.CapTargetList)) + self.CapTargetList = [] + + return FdfProfile + + def ProcessModuleFromPdf(self): + + if self.FdfProfile: + for fvname in self.FvTargetList: + if fvname.upper() not in self.FdfProfile.FvDict: + EdkLogger.error("build", OPTION_VALUE_INVALID, + "No such an FV in FDF file: %s" % fvname) + + # In DSC file may use FILE_GUID to override the module, then in the Platform.Modules use FILE_GUIDmodule.inf as key, + # but the path (self.MetaFile.Path) is the real path + for key in self.FdfProfile.InfDict: + if key == 'ArchTBD': + MetaFile_cache = defaultdict(set) + for Arch in self.ArchList: + Current_Platform_cache = self.BuildDatabase[self.MetaFile, Arch, self.BuildTarget, self.ToolChain] + for Pkey in Current_Platform_cache.Modules: + MetaFile_cache[Arch].add(Current_Platform_cache.Modules[Pkey].MetaFile) + for Inf in self.FdfProfile.InfDict[key]: + ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch) + for Arch in self.ArchList: + if ModuleFile in MetaFile_cache[Arch]: + break + else: + ModuleData = self.BuildDatabase[ModuleFile, Arch, self.BuildTarget, self.ToolChain] + if not ModuleData.IsBinaryModule: + EdkLogger.error('build', PARSER_ERROR, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile) + + else: + for Arch in self.ArchList: + if Arch == key: + Platform = self.BuildDatabase[self.MetaFile, Arch, self.BuildTarget, self.ToolChain] + MetaFileList = set() + for Pkey in Platform.Modules: + MetaFileList.add(Platform.Modules[Pkey].MetaFile) + for Inf in self.FdfProfile.InfDict[key]: + ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch) + if ModuleFile in MetaFileList: + continue + ModuleData = self.BuildDatabase[ModuleFile, Arch, self.BuildTarget, self.ToolChain] + if not ModuleData.IsBinaryModule: + EdkLogger.error('build', PARSER_ERROR, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile) + + + + # parse FDF file to get PCDs in it, if any + def VerifyPcdsFromFDF(self): + + if self.FdfProfile: + PcdSet = self.FdfProfile.PcdDict + self.VerifyPcdDeclearation(PcdSet) + + def ProcessPcdType(self): + for Arch in self.ArchList: + Platform = self.BuildDatabase[self.MetaFile, Arch, self.BuildTarget, self.ToolChain] + Platform.Pcds + # generate the SourcePcdDict and BinaryPcdDict + Libs = [] + for BuildData in list(self.BuildDatabase._CACHE_.values()): + if BuildData.Arch != Arch: + continue + if BuildData.MetaFile.Ext == '.inf' and str(BuildData) in Platform.Modules : + Libs.extend(GetModuleLibInstances(BuildData, Platform, + self.BuildDatabase, + Arch, + self.BuildTarget, + self.ToolChain, + self.Platform.MetaFile, + EdkLogger + )) + for BuildData in list(self.BuildDatabase._CACHE_.values()): + if BuildData.Arch != Arch: + continue + if BuildData.MetaFile.Ext == '.inf': + for key in BuildData.Pcds: + if BuildData.Pcds[key].Pending: + if key in Platform.Pcds: + PcdInPlatform = Platform.Pcds[key] + if PcdInPlatform.Type: + BuildData.Pcds[key].Type = PcdInPlatform.Type + BuildData.Pcds[key].Pending = False + + if BuildData.MetaFile in Platform.Modules: + PlatformModule = Platform.Modules[str(BuildData.MetaFile)] + if key in PlatformModule.Pcds: + PcdInPlatform = PlatformModule.Pcds[key] + if PcdInPlatform.Type: + BuildData.Pcds[key].Type = PcdInPlatform.Type + BuildData.Pcds[key].Pending = False + else: + #Pcd used in Library, Pcd Type from reference module if Pcd Type is Pending + if BuildData.Pcds[key].Pending: + if bool(BuildData.LibraryClass): + if BuildData in set(Libs): + ReferenceModules = BuildData.ReferenceModules + for ReferenceModule in ReferenceModules: + if ReferenceModule.MetaFile in Platform.Modules: + RefPlatformModule = Platform.Modules[str(ReferenceModule.MetaFile)] + if key in RefPlatformModule.Pcds: + PcdInReferenceModule = RefPlatformModule.Pcds[key] + if PcdInReferenceModule.Type: + BuildData.Pcds[key].Type = PcdInReferenceModule.Type + BuildData.Pcds[key].Pending = False + break + + def ProcessMixedPcd(self): + for Arch in self.ArchList: + SourcePcdDict = {TAB_PCDS_DYNAMIC_EX:set(), TAB_PCDS_PATCHABLE_IN_MODULE:set(),TAB_PCDS_DYNAMIC:set(),TAB_PCDS_FIXED_AT_BUILD:set()} + BinaryPcdDict = {TAB_PCDS_DYNAMIC_EX:set(), TAB_PCDS_PATCHABLE_IN_MODULE:set()} + SourcePcdDict_Keys = SourcePcdDict.keys() + BinaryPcdDict_Keys = BinaryPcdDict.keys() + + # generate the SourcePcdDict and BinaryPcdDict + + for BuildData in list(self.BuildDatabase._CACHE_.values()): + if BuildData.Arch != Arch: + continue + if BuildData.MetaFile.Ext == '.inf': + for key in BuildData.Pcds: + if TAB_PCDS_DYNAMIC_EX in BuildData.Pcds[key].Type: + if BuildData.IsBinaryModule: + BinaryPcdDict[TAB_PCDS_DYNAMIC_EX].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName)) + else: + SourcePcdDict[TAB_PCDS_DYNAMIC_EX].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName)) + + elif TAB_PCDS_PATCHABLE_IN_MODULE in BuildData.Pcds[key].Type: + if BuildData.MetaFile.Ext == '.inf': + if BuildData.IsBinaryModule: + BinaryPcdDict[TAB_PCDS_PATCHABLE_IN_MODULE].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName)) + else: + SourcePcdDict[TAB_PCDS_PATCHABLE_IN_MODULE].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName)) + + elif TAB_PCDS_DYNAMIC in BuildData.Pcds[key].Type: + SourcePcdDict[TAB_PCDS_DYNAMIC].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName)) + elif TAB_PCDS_FIXED_AT_BUILD in BuildData.Pcds[key].Type: + SourcePcdDict[TAB_PCDS_FIXED_AT_BUILD].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName)) + + # + # A PCD can only use one type for all source modules + # + for i in SourcePcdDict_Keys: + for j in SourcePcdDict_Keys: + if i != j: + Intersections = SourcePcdDict[i].intersection(SourcePcdDict[j]) + if len(Intersections) > 0: + EdkLogger.error( + 'build', + FORMAT_INVALID, + "Building modules from source INFs, following PCD use %s and %s access method. It must be corrected to use only one access method." % (i, j), + ExtraData='\n\t'.join(str(P[1]+'.'+P[0]) for P in Intersections) + ) + + # + # intersection the BinaryPCD for Mixed PCD + # + for i in BinaryPcdDict_Keys: + for j in BinaryPcdDict_Keys: + if i != j: + Intersections = BinaryPcdDict[i].intersection(BinaryPcdDict[j]) + for item in Intersections: + NewPcd1 = (item[0] + '_' + i, item[1]) + NewPcd2 = (item[0] + '_' + j, item[1]) + if item not in GlobalData.MixedPcd: + GlobalData.MixedPcd[item] = [NewPcd1, NewPcd2] + else: + if NewPcd1 not in GlobalData.MixedPcd[item]: + GlobalData.MixedPcd[item].append(NewPcd1) + if NewPcd2 not in GlobalData.MixedPcd[item]: + GlobalData.MixedPcd[item].append(NewPcd2) + + # + # intersection the SourcePCD and BinaryPCD for Mixed PCD + # + for i in SourcePcdDict_Keys: + for j in BinaryPcdDict_Keys: + if i != j: + Intersections = SourcePcdDict[i].intersection(BinaryPcdDict[j]) + for item in Intersections: + NewPcd1 = (item[0] + '_' + i, item[1]) + NewPcd2 = (item[0] + '_' + j, item[1]) + if item not in GlobalData.MixedPcd: + GlobalData.MixedPcd[item] = [NewPcd1, NewPcd2] + else: + if NewPcd1 not in GlobalData.MixedPcd[item]: + GlobalData.MixedPcd[item].append(NewPcd1) + if NewPcd2 not in GlobalData.MixedPcd[item]: + GlobalData.MixedPcd[item].append(NewPcd2) + + BuildData = self.BuildDatabase[self.MetaFile, Arch, self.BuildTarget, self.ToolChain] + for key in BuildData.Pcds: + for SinglePcd in GlobalData.MixedPcd: + if (BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName) == SinglePcd: + for item in GlobalData.MixedPcd[SinglePcd]: + Pcd_Type = item[0].split('_')[-1] + if (Pcd_Type == BuildData.Pcds[key].Type) or (Pcd_Type == TAB_PCDS_DYNAMIC_EX and BuildData.Pcds[key].Type in PCD_DYNAMIC_EX_TYPE_SET) or \ + (Pcd_Type == TAB_PCDS_DYNAMIC and BuildData.Pcds[key].Type in PCD_DYNAMIC_TYPE_SET): + Value = BuildData.Pcds[key] + Value.TokenCName = BuildData.Pcds[key].TokenCName + '_' + Pcd_Type + if len(key) == 2: + newkey = (Value.TokenCName, key[1]) + elif len(key) == 3: + newkey = (Value.TokenCName, key[1], key[2]) + del BuildData.Pcds[key] + BuildData.Pcds[newkey] = Value + break + break + + if self.FdfProfile: + PcdSet = self.FdfProfile.PcdDict + # handle the mixed pcd in FDF file + for key in PcdSet: + if key in GlobalData.MixedPcd: + Value = PcdSet[key] + del PcdSet[key] + for item in GlobalData.MixedPcd[key]: + PcdSet[item] = Value + + #Collect package set information from INF of FDF + @cached_property + def PkgSet(self): + if not self.FdfFile: + self.FdfFile = self.Platform.FlashDefinition + + if self.FdfFile: + ModuleList = self.FdfProfile.InfList + else: + ModuleList = [] + Pkgs = {} + for Arch in self.ArchList: + Platform = self.BuildDatabase[self.MetaFile, Arch, self.BuildTarget, self.ToolChain] + PkgSet = set() + for mb in [self.BuildDatabase[m, Arch, self.BuildTarget, self.ToolChain] for m in Platform.Modules]: + PkgSet.update(mb.Packages) + for Inf in ModuleList: + ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch) + if ModuleFile in Platform.Modules: + continue + ModuleData = self.BuildDatabase[ModuleFile, Arch, self.BuildTarget, self.ToolChain] + PkgSet.update(ModuleData.Packages) + PkgSet.update(Platform.Packages) + Pkgs[Arch] = list(PkgSet) + return Pkgs + + def VerifyPcdDeclearation(self,PcdSet): + for Arch in self.ArchList: + Platform = self.BuildDatabase[self.MetaFile, Arch, self.BuildTarget, self.ToolChain] + Pkgs = self.PkgSet[Arch] + DecPcds = set() + DecPcdsKey = set() + for Pkg in Pkgs: + for Pcd in Pkg.Pcds: + DecPcds.add((Pcd[0], Pcd[1])) + DecPcdsKey.add((Pcd[0], Pcd[1], Pcd[2])) + + Platform.SkuName = self.SkuId + for Name, Guid,Fileds in PcdSet: + if (Name, Guid) not in DecPcds: + EdkLogger.error( + 'build', + PARSER_ERROR, + "PCD (%s.%s) used in FDF is not declared in DEC files." % (Guid, Name), + File = self.FdfProfile.PcdFileLineDict[Name, Guid, Fileds][0], + Line = self.FdfProfile.PcdFileLineDict[Name, Guid, Fileds][1] + ) + else: + # Check whether Dynamic or DynamicEx PCD used in FDF file. If used, build break and give a error message. + if (Name, Guid, TAB_PCDS_FIXED_AT_BUILD) in DecPcdsKey \ + or (Name, Guid, TAB_PCDS_PATCHABLE_IN_MODULE) in DecPcdsKey \ + or (Name, Guid, TAB_PCDS_FEATURE_FLAG) in DecPcdsKey: + continue + elif (Name, Guid, TAB_PCDS_DYNAMIC) in DecPcdsKey or (Name, Guid, TAB_PCDS_DYNAMIC_EX) in DecPcdsKey: + EdkLogger.error( + 'build', + PARSER_ERROR, + "Using Dynamic or DynamicEx type of PCD [%s.%s] in FDF file is not allowed." % (Guid, Name), + File = self.FdfProfile.PcdFileLineDict[Name, Guid, Fileds][0], + Line = self.FdfProfile.PcdFileLineDict[Name, Guid, Fileds][1] + ) + def CollectAllPcds(self): + + for Arch in self.ArchList: + Pa = PlatformAutoGen(self, self.MetaFile, self.BuildTarget, self.ToolChain, Arch) + # + # Explicitly collect platform's dynamic PCDs + # + Pa.CollectPlatformDynamicPcds() + Pa.CollectFixedAtBuildPcds() + self.AutoGenObjectList.append(Pa) + # We need to calculate the PcdTokenNumber after all Arch Pcds are collected. + for Arch in self.ArchList: + #Pcd TokenNumber + Pa = PlatformAutoGen(self, self.MetaFile, self.BuildTarget, self.ToolChain, Arch) + self.UpdateModuleDataPipe(Arch, {"PCD_TNUM":Pa.PcdTokenNumber}) + + def UpdateModuleDataPipe(self,arch, attr_dict): + for (Target, Toolchain, Arch, MetaFile) in AutoGen.Cache(): + if Arch != arch: + continue + try: + AutoGen.Cache()[(Target, Toolchain, Arch, MetaFile)].DataPipe.DataContainer = attr_dict + except Exception: + pass + # + # Generate Package level hash value + # + def GeneratePkgLevelHash(self): + for Arch in self.ArchList: + GlobalData.gPackageHash = {} + if GlobalData.gUseHashCache: + for Pkg in self.PkgSet[Arch]: + self._GenPkgLevelHash(Pkg) + + + def CreateBuildOptionsFile(self): + # + # Create BuildOptions Macro & PCD metafile, also add the Active Platform and FDF file. + # + content = 'gCommandLineDefines: ' + content += str(GlobalData.gCommandLineDefines) + content += TAB_LINE_BREAK + content += 'BuildOptionPcd: ' + content += str(GlobalData.BuildOptionPcd) + content += TAB_LINE_BREAK + content += 'Active Platform: ' + content += str(self.Platform) + content += TAB_LINE_BREAK + if self.FdfFile: + content += 'Flash Image Definition: ' + content += str(self.FdfFile) + content += TAB_LINE_BREAK + SaveFileOnChange(os.path.join(self.BuildDir, 'BuildOptions'), content, False) + + def CreatePcdTokenNumberFile(self): + # + # Create PcdToken Number file for Dynamic/DynamicEx Pcd. + # + PcdTokenNumber = 'PcdTokenNumber: ' + Pa = self.AutoGenObjectList[0] + if Pa.PcdTokenNumber: + if Pa.DynamicPcdList: + for Pcd in Pa.DynamicPcdList: + PcdTokenNumber += TAB_LINE_BREAK + PcdTokenNumber += str((Pcd.TokenCName, Pcd.TokenSpaceGuidCName)) + PcdTokenNumber += ' : ' + PcdTokenNumber += str(Pa.PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName]) + SaveFileOnChange(os.path.join(self.BuildDir, 'PcdTokenNumber'), PcdTokenNumber, False) + + def GeneratePlatformLevelHash(self): + # + # Get set of workspace metafiles + # + AllWorkSpaceMetaFiles = self._GetMetaFiles(self.BuildTarget, self.ToolChain) + AllWorkSpaceMetaFileList = sorted(AllWorkSpaceMetaFiles, key=lambda x: str(x)) + # + # Retrieve latest modified time of all metafiles + # + SrcTimeStamp = 0 + for f in AllWorkSpaceMetaFiles: + if os.stat(f)[8] > SrcTimeStamp: + SrcTimeStamp = os.stat(f)[8] + self._SrcTimeStamp = SrcTimeStamp + + if GlobalData.gUseHashCache: + FileList = [] + m = hashlib.md5() + for file in AllWorkSpaceMetaFileList: + if file.endswith('.dec'): + continue + f = open(file, 'rb') + Content = f.read() + f.close() + m.update(Content) + FileList.append((str(file), hashlib.md5(Content).hexdigest())) + + HashDir = path.join(self.BuildDir, "Hash_Platform") + HashFile = path.join(HashDir, 'Platform.hash.' + m.hexdigest()) + SaveFileOnChange(HashFile, m.hexdigest(), False) + HashChainFile = path.join(HashDir, 'Platform.hashchain.' + m.hexdigest()) + GlobalData.gPlatformHashFile = HashChainFile + try: + with open(HashChainFile, 'w') as f: + json.dump(FileList, f, indent=2) + except: + EdkLogger.quiet("[cache warning]: fail to save hashchain file:%s" % HashChainFile) + + if GlobalData.gBinCacheDest: + # Copy platform hash files to cache destination + FileDir = path.join(GlobalData.gBinCacheDest, self.OutputDir, self.BuildTarget + "_" + self.ToolChain, "Hash_Platform") + CacheFileDir = FileDir + CreateDirectory(CacheFileDir) + CopyFileOnChange(HashFile, CacheFileDir) + CopyFileOnChange(HashChainFile, CacheFileDir) + + # + # Write metafile list to build directory + # + AutoGenFilePath = os.path.join(self.BuildDir, 'AutoGen') + if os.path.exists (AutoGenFilePath): + os.remove(AutoGenFilePath) + if not os.path.exists(self.BuildDir): + os.makedirs(self.BuildDir) + with open(os.path.join(self.BuildDir, 'AutoGen'), 'w+') as file: + for f in AllWorkSpaceMetaFileList: + print(f, file=file) + return True + + def _GenPkgLevelHash(self, Pkg): + if Pkg.PackageName in GlobalData.gPackageHash: + return + + PkgDir = os.path.join(self.BuildDir, Pkg.Arch, "Hash_Pkg", Pkg.PackageName) + CreateDirectory(PkgDir) + FileList = [] + m = hashlib.md5() + # Get .dec file's hash value + f = open(Pkg.MetaFile.Path, 'rb') + Content = f.read() + f.close() + m.update(Content) + FileList.append((str(Pkg.MetaFile.Path), hashlib.md5(Content).hexdigest())) + # Get include files hash value + if Pkg.Includes: + for inc in sorted(Pkg.Includes, key=lambda x: str(x)): + for Root, Dirs, Files in os.walk(str(inc)): + for File in sorted(Files): + File_Path = os.path.join(Root, File) + f = open(File_Path, 'rb') + Content = f.read() + f.close() + m.update(Content) + FileList.append((str(File_Path), hashlib.md5(Content).hexdigest())) + GlobalData.gPackageHash[Pkg.PackageName] = m.hexdigest() + + HashDir = PkgDir + HashFile = path.join(HashDir, Pkg.PackageName + '.hash.' + m.hexdigest()) + SaveFileOnChange(HashFile, m.hexdigest(), False) + HashChainFile = path.join(HashDir, Pkg.PackageName + '.hashchain.' + m.hexdigest()) + GlobalData.gPackageHashFile[(Pkg.PackageName, Pkg.Arch)] = HashChainFile + try: + with open(HashChainFile, 'w') as f: + json.dump(FileList, f, indent=2) + except: + EdkLogger.quiet("[cache warning]: fail to save hashchain file:%s" % HashChainFile) + + if GlobalData.gBinCacheDest: + # Copy Pkg hash files to cache destination dir + FileDir = path.join(GlobalData.gBinCacheDest, self.OutputDir, self.BuildTarget + "_" + self.ToolChain, Pkg.Arch, "Hash_Pkg", Pkg.PackageName) + CacheFileDir = FileDir + CreateDirectory(CacheFileDir) + CopyFileOnChange(HashFile, CacheFileDir) + CopyFileOnChange(HashChainFile, CacheFileDir) + + def _GetMetaFiles(self, Target, Toolchain): + AllWorkSpaceMetaFiles = set() + # + # add fdf + # + if self.FdfFile: + AllWorkSpaceMetaFiles.add (self.FdfFile.Path) + for f in GlobalData.gFdfParser.GetAllIncludedFile(): + AllWorkSpaceMetaFiles.add (f.FileName) + # + # add dsc + # + AllWorkSpaceMetaFiles.add(self.MetaFile.Path) + + # + # add build_rule.txt & tools_def.txt + # + AllWorkSpaceMetaFiles.add(os.path.join(GlobalData.gConfDirectory, gDefaultBuildRuleFile)) + AllWorkSpaceMetaFiles.add(os.path.join(GlobalData.gConfDirectory, gDefaultToolsDefFile)) + + # add BuildOption metafile + # + AllWorkSpaceMetaFiles.add(os.path.join(self.BuildDir, 'BuildOptions')) + + # add PcdToken Number file for Dynamic/DynamicEx Pcd + # + AllWorkSpaceMetaFiles.add(os.path.join(self.BuildDir, 'PcdTokenNumber')) + + for Pa in self.AutoGenObjectList: + AllWorkSpaceMetaFiles.add(Pa.ToolDefinitionFile) + + for Arch in self.ArchList: + # + # add dec + # + for Package in PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch).PackageList: + AllWorkSpaceMetaFiles.add(Package.MetaFile.Path) + + # + # add included dsc + # + for filePath in self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]._RawData.IncludedFiles: + AllWorkSpaceMetaFiles.add(filePath.Path) + + return AllWorkSpaceMetaFiles + + def _CheckPcdDefineAndType(self): + PcdTypeSet = {TAB_PCDS_FIXED_AT_BUILD, + TAB_PCDS_PATCHABLE_IN_MODULE, + TAB_PCDS_FEATURE_FLAG, + TAB_PCDS_DYNAMIC, + TAB_PCDS_DYNAMIC_EX} + + # This dict store PCDs which are not used by any modules with specified arches + UnusedPcd = OrderedDict() + for Pa in self.AutoGenObjectList: + # Key of DSC's Pcds dictionary is PcdCName, TokenSpaceGuid + for Pcd in Pa.Platform.Pcds: + PcdType = Pa.Platform.Pcds[Pcd].Type + + # If no PCD type, this PCD comes from FDF + if not PcdType: + continue + + # Try to remove Hii and Vpd suffix + if PcdType.startswith(TAB_PCDS_DYNAMIC_EX): + PcdType = TAB_PCDS_DYNAMIC_EX + elif PcdType.startswith(TAB_PCDS_DYNAMIC): + PcdType = TAB_PCDS_DYNAMIC + + for Package in Pa.PackageList: + # Key of DEC's Pcds dictionary is PcdCName, TokenSpaceGuid, PcdType + if (Pcd[0], Pcd[1], PcdType) in Package.Pcds: + break + for Type in PcdTypeSet: + if (Pcd[0], Pcd[1], Type) in Package.Pcds: + EdkLogger.error( + 'build', + FORMAT_INVALID, + "Type [%s] of PCD [%s.%s] in DSC file doesn't match the type [%s] defined in DEC file." \ + % (Pa.Platform.Pcds[Pcd].Type, Pcd[1], Pcd[0], Type), + ExtraData=None + ) + return + else: + UnusedPcd.setdefault(Pcd, []).append(Pa.Arch) + + for Pcd in UnusedPcd: + EdkLogger.warn( + 'build', + "The PCD was not specified by any INF module in the platform for the given architecture.\n" + "\tPCD: [%s.%s]\n\tPlatform: [%s]\n\tArch: %s" + % (Pcd[1], Pcd[0], os.path.basename(str(self.MetaFile)), str(UnusedPcd[Pcd])), + ExtraData=None + ) + + def __repr__(self): + return "%s [%s]" % (self.MetaFile, ", ".join(self.ArchList)) + + ## Return the directory to store FV files + @cached_property + def FvDir(self): + return path.join(self.BuildDir, TAB_FV_DIRECTORY) + + ## Return the directory to store all intermediate and final files built + @cached_property + def BuildDir(self): + return self.AutoGenObjectList[0].BuildDir + + ## Return the build output directory platform specifies + @cached_property + def OutputDir(self): + return self.Platform.OutputDirectory + + ## Return platform name + @cached_property + def Name(self): + return self.Platform.PlatformName + + ## Return meta-file GUID + @cached_property + def Guid(self): + return self.Platform.Guid + + ## Return platform version + @cached_property + def Version(self): + return self.Platform.Version + + ## Return paths of tools + @cached_property + def ToolDefinition(self): + return self.AutoGenObjectList[0].ToolDefinition + + ## Return directory of platform makefile + # + # @retval string Makefile directory + # + @cached_property + def MakeFileDir(self): + return self.BuildDir + + ## Return build command string + # + # @retval string Build command string + # + @cached_property + def BuildCommand(self): + # BuildCommand should be all the same. So just get one from platform AutoGen + return self.AutoGenObjectList[0].BuildCommand + + ## Check the PCDs token value conflict in each DEC file. + # + # Will cause build break and raise error message while two PCDs conflict. + # + # @return None + # + def _CheckAllPcdsTokenValueConflict(self): + for Pa in self.AutoGenObjectList: + for Package in Pa.PackageList: + PcdList = list(Package.Pcds.values()) + PcdList.sort(key=lambda x: int(x.TokenValue, 0)) + Count = 0 + while (Count < len(PcdList) - 1) : + Item = PcdList[Count] + ItemNext = PcdList[Count + 1] + # + # Make sure in the same token space the TokenValue should be unique + # + if (int(Item.TokenValue, 0) == int(ItemNext.TokenValue, 0)): + SameTokenValuePcdList = [] + SameTokenValuePcdList.append(Item) + SameTokenValuePcdList.append(ItemNext) + RemainPcdListLength = len(PcdList) - Count - 2 + for ValueSameCount in range(RemainPcdListLength): + if int(PcdList[len(PcdList) - RemainPcdListLength + ValueSameCount].TokenValue, 0) == int(Item.TokenValue, 0): + SameTokenValuePcdList.append(PcdList[len(PcdList) - RemainPcdListLength + ValueSameCount]) + else: + break; + # + # Sort same token value PCD list with TokenGuid and TokenCName + # + SameTokenValuePcdList.sort(key=lambda x: "%s.%s" % (x.TokenSpaceGuidCName, x.TokenCName)) + SameTokenValuePcdListCount = 0 + while (SameTokenValuePcdListCount < len(SameTokenValuePcdList) - 1): + Flag = False + TemListItem = SameTokenValuePcdList[SameTokenValuePcdListCount] + TemListItemNext = SameTokenValuePcdList[SameTokenValuePcdListCount + 1] + + if (TemListItem.TokenSpaceGuidCName == TemListItemNext.TokenSpaceGuidCName) and (TemListItem.TokenCName != TemListItemNext.TokenCName): + for PcdItem in GlobalData.MixedPcd: + if (TemListItem.TokenCName, TemListItem.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem] or \ + (TemListItemNext.TokenCName, TemListItemNext.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]: + Flag = True + if not Flag: + EdkLogger.error( + 'build', + FORMAT_INVALID, + "The TokenValue [%s] of PCD [%s.%s] is conflict with: [%s.%s] in %s"\ + % (TemListItem.TokenValue, TemListItem.TokenSpaceGuidCName, TemListItem.TokenCName, TemListItemNext.TokenSpaceGuidCName, TemListItemNext.TokenCName, Package), + ExtraData=None + ) + SameTokenValuePcdListCount += 1 + Count += SameTokenValuePcdListCount + Count += 1 + + PcdList = list(Package.Pcds.values()) + PcdList.sort(key=lambda x: "%s.%s" % (x.TokenSpaceGuidCName, x.TokenCName)) + Count = 0 + while (Count < len(PcdList) - 1) : + Item = PcdList[Count] + ItemNext = PcdList[Count + 1] + # + # Check PCDs with same TokenSpaceGuidCName.TokenCName have same token value as well. + # + if (Item.TokenSpaceGuidCName == ItemNext.TokenSpaceGuidCName) and (Item.TokenCName == ItemNext.TokenCName) and (int(Item.TokenValue, 0) != int(ItemNext.TokenValue, 0)): + EdkLogger.error( + 'build', + FORMAT_INVALID, + "The TokenValue [%s] of PCD [%s.%s] in %s defined in two places should be same as well."\ + % (Item.TokenValue, Item.TokenSpaceGuidCName, Item.TokenCName, Package), + ExtraData=None + ) + Count += 1 + ## Generate fds command + @property + def GenFdsCommand(self): + return (GenMake.TopLevelMakefile(self)._TEMPLATE_.Replace(GenMake.TopLevelMakefile(self)._TemplateDict)).strip() + + @property + def GenFdsCommandDict(self): + FdsCommandDict = {} + LogLevel = EdkLogger.GetLevel() + if LogLevel == EdkLogger.VERBOSE: + FdsCommandDict["verbose"] = True + elif LogLevel <= EdkLogger.DEBUG_9: + FdsCommandDict["debug"] = LogLevel - 1 + elif LogLevel == EdkLogger.QUIET: + FdsCommandDict["quiet"] = True + + FdsCommandDict["GenfdsMultiThread"] = GlobalData.gEnableGenfdsMultiThread + if GlobalData.gIgnoreSource: + FdsCommandDict["IgnoreSources"] = True + + FdsCommandDict["OptionPcd"] = [] + for pcd in GlobalData.BuildOptionPcd: + if pcd[2]: + pcdname = '.'.join(pcd[0:3]) + else: + pcdname = '.'.join(pcd[0:2]) + if pcd[3].startswith('{'): + FdsCommandDict["OptionPcd"].append(pcdname + '=' + 'H' + '"' + pcd[3] + '"') + else: + FdsCommandDict["OptionPcd"].append(pcdname + '=' + pcd[3]) + + MacroList = [] + # macros passed to GenFds + MacroDict = {} + MacroDict.update(GlobalData.gGlobalDefines) + MacroDict.update(GlobalData.gCommandLineDefines) + for MacroName in MacroDict: + if MacroDict[MacroName] != "": + MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\'))) + else: + MacroList.append('"%s"' % MacroName) + FdsCommandDict["macro"] = MacroList + + FdsCommandDict["fdf_file"] = [self.FdfFile] + FdsCommandDict["build_target"] = self.BuildTarget + FdsCommandDict["toolchain_tag"] = self.ToolChain + FdsCommandDict["active_platform"] = str(self) + + FdsCommandDict["conf_directory"] = GlobalData.gConfDirectory + FdsCommandDict["build_architecture_list"] = ','.join(self.ArchList) + FdsCommandDict["platform_build_directory"] = self.BuildDir + + FdsCommandDict["fd"] = self.FdTargetList + FdsCommandDict["fv"] = self.FvTargetList + FdsCommandDict["cap"] = self.CapTargetList + return FdsCommandDict + + ## Create makefile for the platform and modules in it + # + # @param CreateDepsMakeFile Flag indicating if the makefile for + # modules will be created as well + # + def CreateMakeFile(self, CreateDepsMakeFile=False): + if not CreateDepsMakeFile: + return + for Pa in self.AutoGenObjectList: + Pa.CreateMakeFile(CreateDepsMakeFile) + + ## Create autogen code for platform and modules + # + # Since there's no autogen code for platform, this method will do nothing + # if CreateModuleCodeFile is set to False. + # + # @param CreateDepsCodeFile Flag indicating if creating module's + # autogen code file or not + # + def CreateCodeFile(self, CreateDepsCodeFile=False): + if not CreateDepsCodeFile: + return + for Pa in self.AutoGenObjectList: + Pa.CreateCodeFile(CreateDepsCodeFile) + + ## Create AsBuilt INF file the platform + # + def CreateAsBuiltInf(self): + return + |