| ## @file | |
| # This file is used to create a database used by build tool | |
| # | |
| # Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR> | |
| # (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> | |
| # SPDX-License-Identifier: BSD-2-Clause-Patent | |
| # | |
| from Common.StringUtils import * | |
| from Common.DataType import * | |
| from Common.Misc import * | |
| from types import * | |
| from collections import OrderedDict | |
| from CommonDataClass.DataClass import * | |
| from Workspace.BuildClassObject import PackageBuildClassObject, StructurePcd, PcdClassObject | |
| from Common.GlobalData import gGlobalDefines | |
| from re import compile | |
| ## Platform build information from DEC file | |
| # | |
| # This class is used to retrieve information stored in database and convert them | |
| # into PackageBuildClassObject form for easier use for AutoGen. | |
| # | |
| class DecBuildData(PackageBuildClassObject): | |
| # dict used to convert part of [Defines] to members of DecBuildData directly | |
| _PROPERTY_ = { | |
| # | |
| # Required Fields | |
| # | |
| TAB_DEC_DEFINES_PACKAGE_NAME : "_PackageName", | |
| TAB_DEC_DEFINES_PACKAGE_GUID : "_Guid", | |
| TAB_DEC_DEFINES_PACKAGE_VERSION : "_Version", | |
| TAB_DEC_DEFINES_PKG_UNI_FILE : "_PkgUniFile", | |
| } | |
| ## Constructor of DecBuildData | |
| # | |
| # Initialize object of DecBuildData | |
| # | |
| # @param FilePath The path of package description file | |
| # @param RawData The raw data of DEC file | |
| # @param BuildDataBase Database used to retrieve module information | |
| # @param Arch The target architecture | |
| # @param Platform (not used for DecBuildData) | |
| # @param Macros Macros used for replacement in DSC file | |
| # | |
| def __init__(self, File, RawData, BuildDataBase, Arch=TAB_ARCH_COMMON, Target=None, Toolchain=None): | |
| self.MetaFile = File | |
| self._PackageDir = File.Dir | |
| self._RawData = RawData | |
| self._Bdb = BuildDataBase | |
| self._Arch = Arch | |
| self._Target = Target | |
| self._Toolchain = Toolchain | |
| self._Clear() | |
| self.UpdatePcdTypeDict() | |
| ## XXX[key] = value | |
| def __setitem__(self, key, value): | |
| self.__dict__[self._PROPERTY_[key]] = value | |
| ## value = XXX[key] | |
| def __getitem__(self, key): | |
| return self.__dict__[self._PROPERTY_[key]] | |
| ## "in" test support | |
| def __contains__(self, key): | |
| return key in self._PROPERTY_ | |
| ## Set all internal used members of DecBuildData to None | |
| def _Clear(self): | |
| self._Header = None | |
| self._PackageName = None | |
| self._Guid = None | |
| self._Version = None | |
| self._PkgUniFile = None | |
| self._Protocols = None | |
| self._Ppis = None | |
| self._Guids = None | |
| self._Includes = None | |
| self._CommonIncludes = None | |
| self._LibraryClasses = None | |
| self._Pcds = None | |
| self._MacroDict = None | |
| self._PrivateProtocols = None | |
| self._PrivatePpis = None | |
| self._PrivateGuids = None | |
| self._PrivateIncludes = None | |
| ## Get current effective macros | |
| @property | |
| def _Macros(self): | |
| if self._MacroDict is None: | |
| self._MacroDict = dict(gGlobalDefines) | |
| return self._MacroDict | |
| ## Get architecture | |
| @property | |
| def Arch(self): | |
| return self._Arch | |
| ## Retrieve all information in [Defines] section | |
| # | |
| # (Retrieving all [Defines] information in one-shot is just to save time.) | |
| # | |
| def _GetHeaderInfo(self): | |
| RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch] | |
| for Record in RecordList: | |
| Name = Record[1] | |
| if Name in self: | |
| self[Name] = Record[2] | |
| self._Header = 'DUMMY' | |
| ## Retrieve package name | |
| @property | |
| def PackageName(self): | |
| if self._PackageName is None: | |
| if self._Header is None: | |
| self._GetHeaderInfo() | |
| if self._PackageName is None: | |
| EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_NAME", File=self.MetaFile) | |
| return self._PackageName | |
| ## Retrieve file guid | |
| @property | |
| def PackageName(self): | |
| if self._Guid is None: | |
| if self._Header is None: | |
| self._GetHeaderInfo() | |
| if self._Guid is None: | |
| EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_GUID", File=self.MetaFile) | |
| return self._Guid | |
| ## Retrieve package version | |
| @property | |
| def Version(self): | |
| if self._Version is None: | |
| if self._Header is None: | |
| self._GetHeaderInfo() | |
| if self._Version is None: | |
| self._Version = '' | |
| return self._Version | |
| ## Retrieve protocol definitions (name/value pairs) | |
| @property | |
| def Protocols(self): | |
| if self._Protocols is None: | |
| # | |
| # tdict is a special kind of dict, used for selecting correct | |
| # protocol definition for given ARCH | |
| # | |
| ProtocolDict = tdict(True) | |
| PrivateProtocolDict = tdict(True) | |
| NameList = [] | |
| PrivateNameList = [] | |
| PublicNameList = [] | |
| # find out all protocol definitions for specific and 'common' arch | |
| RecordList = self._RawData[MODEL_EFI_PROTOCOL, self._Arch] | |
| for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList: | |
| if PrivateFlag == 'PRIVATE': | |
| if Name not in PrivateNameList: | |
| PrivateNameList.append(Name) | |
| PrivateProtocolDict[Arch, Name] = Guid | |
| if Name in PublicNameList: | |
| EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo) | |
| else: | |
| if Name not in PublicNameList: | |
| PublicNameList.append(Name) | |
| if Name in PrivateNameList: | |
| EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo) | |
| if Name not in NameList: | |
| NameList.append(Name) | |
| ProtocolDict[Arch, Name] = Guid | |
| # use OrderedDict to keep the order | |
| self._Protocols = OrderedDict() | |
| self._PrivateProtocols = OrderedDict() | |
| for Name in NameList: | |
| # | |
| # limit the ARCH to self._Arch, if no self._Arch found, tdict | |
| # will automatically turn to 'common' ARCH for trying | |
| # | |
| self._Protocols[Name] = ProtocolDict[self._Arch, Name] | |
| for Name in PrivateNameList: | |
| self._PrivateProtocols[Name] = PrivateProtocolDict[self._Arch, Name] | |
| return self._Protocols | |
| ## Retrieve PPI definitions (name/value pairs) | |
| @property | |
| def Ppis(self): | |
| if self._Ppis is None: | |
| # | |
| # tdict is a special kind of dict, used for selecting correct | |
| # PPI definition for given ARCH | |
| # | |
| PpiDict = tdict(True) | |
| PrivatePpiDict = tdict(True) | |
| NameList = [] | |
| PrivateNameList = [] | |
| PublicNameList = [] | |
| # find out all PPI definitions for specific arch and 'common' arch | |
| RecordList = self._RawData[MODEL_EFI_PPI, self._Arch] | |
| for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList: | |
| if PrivateFlag == 'PRIVATE': | |
| if Name not in PrivateNameList: | |
| PrivateNameList.append(Name) | |
| PrivatePpiDict[Arch, Name] = Guid | |
| if Name in PublicNameList: | |
| EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo) | |
| else: | |
| if Name not in PublicNameList: | |
| PublicNameList.append(Name) | |
| if Name in PrivateNameList: | |
| EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo) | |
| if Name not in NameList: | |
| NameList.append(Name) | |
| PpiDict[Arch, Name] = Guid | |
| # use OrderedDict to keep the order | |
| self._Ppis = OrderedDict() | |
| self._PrivatePpis = OrderedDict() | |
| for Name in NameList: | |
| # | |
| # limit the ARCH to self._Arch, if no self._Arch found, tdict | |
| # will automatically turn to 'common' ARCH for trying | |
| # | |
| self._Ppis[Name] = PpiDict[self._Arch, Name] | |
| for Name in PrivateNameList: | |
| self._PrivatePpis[Name] = PrivatePpiDict[self._Arch, Name] | |
| return self._Ppis | |
| ## Retrieve GUID definitions (name/value pairs) | |
| @property | |
| def Guids(self): | |
| if self._Guids is None: | |
| # | |
| # tdict is a special kind of dict, used for selecting correct | |
| # GUID definition for given ARCH | |
| # | |
| GuidDict = tdict(True) | |
| PrivateGuidDict = tdict(True) | |
| NameList = [] | |
| PrivateNameList = [] | |
| PublicNameList = [] | |
| # find out all protocol definitions for specific and 'common' arch | |
| RecordList = self._RawData[MODEL_EFI_GUID, self._Arch] | |
| for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList: | |
| if PrivateFlag == 'PRIVATE': | |
| if Name not in PrivateNameList: | |
| PrivateNameList.append(Name) | |
| PrivateGuidDict[Arch, Name] = Guid | |
| if Name in PublicNameList: | |
| EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo) | |
| else: | |
| if Name not in PublicNameList: | |
| PublicNameList.append(Name) | |
| if Name in PrivateNameList: | |
| EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo) | |
| if Name not in NameList: | |
| NameList.append(Name) | |
| GuidDict[Arch, Name] = Guid | |
| # use OrderedDict to keep the order | |
| self._Guids = OrderedDict() | |
| self._PrivateGuids = OrderedDict() | |
| for Name in NameList: | |
| # | |
| # limit the ARCH to self._Arch, if no self._Arch found, tdict | |
| # will automatically turn to 'common' ARCH for trying | |
| # | |
| self._Guids[Name] = GuidDict[self._Arch, Name] | |
| for Name in PrivateNameList: | |
| self._PrivateGuids[Name] = PrivateGuidDict[self._Arch, Name] | |
| return self._Guids | |
| ## Retrieve public include paths declared in this package | |
| @property | |
| def Includes(self): | |
| if self._Includes is None or self._CommonIncludes is None: | |
| self._CommonIncludes = [] | |
| self._Includes = [] | |
| self._PrivateIncludes = [] | |
| PublicInclues = [] | |
| RecordList = self._RawData[MODEL_EFI_INCLUDE, self._Arch] | |
| Macros = self._Macros | |
| for Record in RecordList: | |
| File = PathClass(NormPath(Record[0], Macros), self._PackageDir, Arch=self._Arch) | |
| LineNo = Record[-1] | |
| # validate the path | |
| ErrorCode, ErrorInfo = File.Validate() | |
| if ErrorCode != 0: | |
| EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo) | |
| # avoid duplicate include path | |
| if File not in self._Includes: | |
| self._Includes.append(File) | |
| if Record[4] == 'PRIVATE': | |
| if File not in self._PrivateIncludes: | |
| self._PrivateIncludes.append(File) | |
| if File in PublicInclues: | |
| EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % File, File=self.MetaFile, Line=LineNo) | |
| else: | |
| if File not in PublicInclues: | |
| PublicInclues.append(File) | |
| if File in self._PrivateIncludes: | |
| EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % File, File=self.MetaFile, Line=LineNo) | |
| if Record[3] == TAB_COMMON: | |
| self._CommonIncludes.append(File) | |
| return self._Includes | |
| ## Retrieve library class declarations (not used in build at present) | |
| @property | |
| def LibraryClasses(self): | |
| if self._LibraryClasses is None: | |
| # | |
| # tdict is a special kind of dict, used for selecting correct | |
| # library class declaration for given ARCH | |
| # | |
| LibraryClassDict = tdict(True) | |
| LibraryClassSet = set() | |
| RecordList = self._RawData[MODEL_EFI_LIBRARY_CLASS, self._Arch] | |
| Macros = self._Macros | |
| for LibraryClass, File, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList: | |
| File = PathClass(NormPath(File, Macros), self._PackageDir, Arch=self._Arch) | |
| # check the file validation | |
| ErrorCode, ErrorInfo = File.Validate() | |
| if ErrorCode != 0: | |
| EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo) | |
| LibraryClassSet.add(LibraryClass) | |
| LibraryClassDict[Arch, LibraryClass] = File | |
| self._LibraryClasses = OrderedDict() | |
| for LibraryClass in LibraryClassSet: | |
| self._LibraryClasses[LibraryClass] = LibraryClassDict[self._Arch, LibraryClass] | |
| return self._LibraryClasses | |
| ## Retrieve PCD declarations | |
| @property | |
| def Pcds(self): | |
| if self._Pcds is None: | |
| self._Pcds = OrderedDict() | |
| self._Pcds.update(self._GetPcd(MODEL_PCD_FIXED_AT_BUILD)) | |
| self._Pcds.update(self._GetPcd(MODEL_PCD_PATCHABLE_IN_MODULE)) | |
| self._Pcds.update(self._GetPcd(MODEL_PCD_FEATURE_FLAG)) | |
| self._Pcds.update(self._GetPcd(MODEL_PCD_DYNAMIC)) | |
| self._Pcds.update(self._GetPcd(MODEL_PCD_DYNAMIC_EX)) | |
| return self._Pcds | |
| def ParsePcdName(self,TokenCName): | |
| TokenCName = TokenCName.strip() | |
| if TokenCName.startswith("["): | |
| if "." in TokenCName: | |
| Demesionattr = TokenCName[:TokenCName.index(".")] | |
| Fields = TokenCName[TokenCName.index(".")+1:] | |
| else: | |
| Demesionattr = TokenCName | |
| Fields = "" | |
| else: | |
| Demesionattr = "" | |
| Fields = TokenCName | |
| return Demesionattr,Fields | |
| def ProcessStructurePcd(self, StructurePcdRawDataSet): | |
| s_pcd_set = OrderedDict() | |
| for s_pcd, LineNo in StructurePcdRawDataSet: | |
| if s_pcd.TokenSpaceGuidCName not in s_pcd_set: | |
| s_pcd_set[s_pcd.TokenSpaceGuidCName] = [] | |
| s_pcd_set[s_pcd.TokenSpaceGuidCName].append((s_pcd, LineNo)) | |
| str_pcd_set = [] | |
| for pcdname in s_pcd_set: | |
| dep_pkgs = [] | |
| struct_pcd = StructurePcd() | |
| for item, LineNo in s_pcd_set[pcdname]: | |
| if not item.TokenCName: | |
| continue | |
| if "<HeaderFiles>" in item.TokenCName: | |
| struct_pcd.StructuredPcdIncludeFile.append(item.DefaultValue) | |
| elif "<Packages>" in item.TokenCName: | |
| dep_pkgs.append(item.DefaultValue) | |
| elif item.DatumType == item.TokenCName: | |
| struct_pcd.copy(item) | |
| struct_pcd.TokenValue = struct_pcd.TokenValue.strip("{").strip() | |
| struct_pcd.TokenSpaceGuidCName, struct_pcd.TokenCName = pcdname.split(".") | |
| struct_pcd.PcdDefineLineNo = LineNo | |
| struct_pcd.PkgPath = self.MetaFile.File | |
| struct_pcd.SetDecDefaultValue(item.DefaultValue,self.MetaFile.File,LineNo) | |
| else: | |
| DemesionAttr, Fields = self.ParsePcdName(item.TokenCName) | |
| struct_pcd.AddDefaultValue(Fields, item.DefaultValue, self.MetaFile.File, LineNo,DemesionAttr) | |
| struct_pcd.PackageDecs = dep_pkgs | |
| str_pcd_set.append(struct_pcd) | |
| return str_pcd_set | |
| ## Retrieve PCD declarations for given type | |
| def _GetPcd(self, Type): | |
| Pcds = OrderedDict() | |
| # | |
| # tdict is a special kind of dict, used for selecting correct | |
| # PCD declaration for given ARCH | |
| # | |
| PcdDict = tdict(True, 3) | |
| # for summarizing PCD | |
| PcdSet = [] | |
| # find out all PCDs of the 'type' | |
| StrPcdSet = [] | |
| RecordList = self._RawData[Type, self._Arch] | |
| for TokenSpaceGuid, PcdCName, Setting, Arch, PrivateFlag, Dummy1, Dummy2 in RecordList: | |
| PcdDict[Arch, PcdCName, TokenSpaceGuid] = (Setting, Dummy2) | |
| if not (PcdCName, TokenSpaceGuid) in PcdSet: | |
| PcdSet.append((PcdCName, TokenSpaceGuid)) | |
| DefinitionPosition = {} | |
| for PcdCName, TokenSpaceGuid in PcdSet: | |
| # | |
| # limit the ARCH to self._Arch, if no self._Arch found, tdict | |
| # will automatically turn to 'common' ARCH and try again | |
| # | |
| Setting, LineNo = PcdDict[self._Arch, PcdCName, TokenSpaceGuid] | |
| if Setting is None: | |
| continue | |
| DefaultValue, DatumType, TokenNumber = AnalyzePcdData(Setting) | |
| validateranges, validlists, expressions = self._RawData.GetValidExpression(TokenSpaceGuid, PcdCName) | |
| PcdObj = PcdClassObject( | |
| PcdCName, | |
| TokenSpaceGuid, | |
| self._PCD_TYPE_STRING_[Type], | |
| DatumType, | |
| DefaultValue, | |
| TokenNumber, | |
| '', | |
| {}, | |
| False, | |
| None, | |
| list(validateranges), | |
| list(validlists), | |
| list(expressions) | |
| ) | |
| DefinitionPosition[PcdObj] = (self.MetaFile.File, LineNo) | |
| if "." in TokenSpaceGuid: | |
| StrPcdSet.append((PcdObj, LineNo)) | |
| else: | |
| Pcds[PcdCName, TokenSpaceGuid, self._PCD_TYPE_STRING_[Type]] = PcdObj | |
| StructurePcds = self.ProcessStructurePcd(StrPcdSet) | |
| for pcd in StructurePcds: | |
| Pcds[pcd.TokenCName, pcd.TokenSpaceGuidCName, self._PCD_TYPE_STRING_[Type]] = pcd | |
| StructPattern = compile(r'[_a-zA-Z][0-9A-Za-z_]*$') | |
| for pcd in Pcds.values(): | |
| if pcd.DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]: | |
| if not pcd.IsAggregateDatumType(): | |
| EdkLogger.error('build', FORMAT_INVALID, "DatumType only support BOOLEAN, UINT8, UINT16, UINT32, UINT64, VOID* or a valid struct name.", DefinitionPosition[pcd][0], DefinitionPosition[pcd][1]) | |
| elif not pcd.IsArray() and not pcd.StructuredPcdIncludeFile: | |
| EdkLogger.error("build", PCD_STRUCTURE_PCD_ERROR, "The structure Pcd %s.%s header file is not found in %s line %s \n" % (pcd.TokenSpaceGuidCName, pcd.TokenCName, pcd.DefinitionPosition[0], pcd.DefinitionPosition[1] )) | |
| return Pcds | |
| @property | |
| def CommonIncludes(self): | |
| if self._CommonIncludes is None: | |
| self.Includes | |
| return self._CommonIncludes |