mirror of https://github.com/acidanthera/audk.git
480 lines
22 KiB
Python
480 lines
22 KiB
Python
## @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>
|
|
# 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.StringUtils import *
|
|
from Common.DataType import *
|
|
from Common.Misc import *
|
|
from types import *
|
|
from collections import OrderedDict
|
|
|
|
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 : TAB_PCDS_FIXED_AT_BUILD,
|
|
MODEL_PCD_PATCHABLE_IN_MODULE : TAB_PCDS_PATCHABLE_IN_MODULE,
|
|
MODEL_PCD_FEATURE_FLAG : TAB_PCDS_FEATURE_FLAG,
|
|
MODEL_PCD_DYNAMIC : TAB_PCDS_DYNAMIC,
|
|
MODEL_PCD_DYNAMIC_DEFAULT : TAB_PCDS_DYNAMIC,
|
|
MODEL_PCD_DYNAMIC_HII : TAB_PCDS_DYNAMIC_HII,
|
|
MODEL_PCD_DYNAMIC_VPD : TAB_PCDS_DYNAMIC_VPD,
|
|
MODEL_PCD_DYNAMIC_EX : TAB_PCDS_DYNAMIC_EX,
|
|
MODEL_PCD_DYNAMIC_EX_DEFAULT : TAB_PCDS_DYNAMIC_EX,
|
|
MODEL_PCD_DYNAMIC_EX_HII : TAB_PCDS_DYNAMIC_EX_HII,
|
|
MODEL_PCD_DYNAMIC_EX_VPD : TAB_PCDS_DYNAMIC_EX_VPD,
|
|
}
|
|
|
|
# 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()
|
|
|
|
## 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(GlobalData.gGlobalDefines)
|
|
return self._MacroDict
|
|
|
|
## Get architecture
|
|
@property
|
|
def Arch(self):
|
|
return self._Arch
|
|
|
|
## 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
|
|
@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 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 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 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 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 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 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
|
|
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)
|
|
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)
|
|
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
|
|
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
|