| # # @file |
| # This file is used to create a database used by build tool |
| # |
| # Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> |
| # (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> |
| # This program and the accompanying materials |
| # are licensed and made available under the terms and conditions of the BSD License |
| # which accompanies this distribution. The full text of the license may be found at |
| # http://opensource.org/licenses/bsd-license.php |
| # |
| # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. |
| # |
| from Common.String import * |
| from Common.DataType import * |
| from Common.Misc import * |
| from types import * |
| |
| from Workspace.BuildClassObject import PackageBuildClassObject, StructurePcd, PcdClassObject |
| |
| # # 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 PCD type in database to string used by build tool |
| _PCD_TYPE_STRING_ = { |
| MODEL_PCD_FIXED_AT_BUILD : "FixedAtBuild", |
| MODEL_PCD_PATCHABLE_IN_MODULE : "PatchableInModule", |
| MODEL_PCD_FEATURE_FLAG : "FeatureFlag", |
| MODEL_PCD_DYNAMIC : "Dynamic", |
| MODEL_PCD_DYNAMIC_DEFAULT : "Dynamic", |
| MODEL_PCD_DYNAMIC_HII : "DynamicHii", |
| MODEL_PCD_DYNAMIC_VPD : "DynamicVpd", |
| MODEL_PCD_DYNAMIC_EX : "DynamicEx", |
| MODEL_PCD_DYNAMIC_EX_DEFAULT : "DynamicEx", |
| MODEL_PCD_DYNAMIC_EX_HII : "DynamicExHii", |
| MODEL_PCD_DYNAMIC_EX_VPD : "DynamicExVpd", |
| } |
| |
| # 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='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() |
| |
| # # 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._LibraryClasses = None |
| self._Pcds = None |
| self.__Macros = None |
| self._PrivateProtocols = None |
| self._PrivatePpis = None |
| self._PrivateGuids = None |
| self._PrivateIncludes = None |
| |
| # # Get current effective macros |
| def _GetMacros(self): |
| if self.__Macros == None: |
| self.__Macros = {} |
| self.__Macros.update(GlobalData.gGlobalDefines) |
| return self.__Macros |
| |
| # # Get architecture |
| def _GetArch(self): |
| return self._Arch |
| |
| # # Set architecture |
| # |
| # Changing the default ARCH to another may affect all other information |
| # because all information in a platform may be ARCH-related. That's |
| # why we need to clear all internal used members, in order to cause all |
| # information to be re-retrieved. |
| # |
| # @param Value The value of ARCH |
| # |
| def _SetArch(self, Value): |
| if self._Arch == Value: |
| return |
| self._Arch = Value |
| self._Clear() |
| |
| # # Retrieve all information in [Defines] section |
| # |
| # (Retriving 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 |
| def _GetPackageName(self): |
| if self._PackageName == None: |
| if self._Header == None: |
| self._GetHeaderInfo() |
| if self._PackageName == None: |
| EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_NAME", File=self.MetaFile) |
| return self._PackageName |
| |
| # # Retrieve file guid |
| def _GetFileGuid(self): |
| if self._Guid == None: |
| if self._Header == None: |
| self._GetHeaderInfo() |
| if self._Guid == None: |
| EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_GUID", File=self.MetaFile) |
| return self._Guid |
| |
| # # Retrieve package version |
| def _GetVersion(self): |
| if self._Version == None: |
| if self._Header == None: |
| self._GetHeaderInfo() |
| if self._Version == None: |
| self._Version = '' |
| return self._Version |
| |
| # # Retrieve protocol definitions (name/value pairs) |
| def _GetProtocol(self): |
| if self._Protocols == None: |
| # |
| # tdict is a special kind of dict, used for selecting correct |
| # protocol defition 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 sdict to keep the order |
| self._Protocols = sdict() |
| self._PrivateProtocols = sdict() |
| 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) |
| def _GetPpi(self): |
| if self._Ppis == None: |
| # |
| # tdict is a special kind of dict, used for selecting correct |
| # PPI defition 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 sdict to keep the order |
| self._Ppis = sdict() |
| self._PrivatePpis = sdict() |
| 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) |
| def _GetGuid(self): |
| if self._Guids == None: |
| # |
| # tdict is a special kind of dict, used for selecting correct |
| # GUID defition 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 sdict to keep the order |
| self._Guids = sdict() |
| self._PrivateGuids = sdict() |
| 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 |
| def _GetInclude(self): |
| if self._Includes == None: |
| self._Includes = [] |
| self._PrivateIncludes = [] |
| PublicInclues = [] |
| RecordList = self._RawData[MODEL_EFI_INCLUDE, self._Arch] |
| Macros = self._Macros |
| Macros["EDK_SOURCE"] = GlobalData.gEcpSource |
| 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) |
| |
| return self._Includes |
| |
| # # Retrieve library class declarations (not used in build at present) |
| def _GetLibraryClass(self): |
| if self._LibraryClasses == 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 = sdict() |
| for LibraryClass in LibraryClassSet: |
| self._LibraryClasses[LibraryClass] = LibraryClassDict[self._Arch, LibraryClass] |
| return self._LibraryClasses |
| |
| # # Retrieve PCD declarations |
| def _GetPcds(self): |
| if self._Pcds == None: |
| self._Pcds = sdict() |
| 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 ProcessStructurePcd(self, StructurePcdRawDataSet): |
| s_pcd_set = dict() |
| 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 "<HeaderFiles>" in item.TokenCName: |
| struct_pcd.StructuredPcdIncludeFile = 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(".") |
| else: |
| struct_pcd.AddDefaultValue(item.TokenCName, item.DefaultValue,self.MetaFile.File,LineNo) |
| |
| 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 = sdict() |
| # |
| # 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)) |
| |
| 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 == 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) |
| ) |
| 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 |
| |
| return Pcds |
| |
| |
| _Macros = property(_GetMacros) |
| Arch = property(_GetArch, _SetArch) |
| PackageName = property(_GetPackageName) |
| Guid = property(_GetFileGuid) |
| Version = property(_GetVersion) |
| |
| Protocols = property(_GetProtocol) |
| Ppis = property(_GetPpi) |
| Guids = property(_GetGuid) |
| Includes = property(_GetInclude) |
| LibraryClasses = property(_GetLibraryClass) |
| Pcds = property(_GetPcds) |